Is Javascript/jQuery DOM creation safe until it’s added to the document?

Is this by itself dangerous in any
way? My point being, can just the
simple act of creating a DOM somehow
inject anything, or is it just simply
processed and the structure is
created?

Simply creating an element without appending it to the dom will not cause any script to run since it is purely an object at this point (HtmlScriptElement). When it is actually appended to the dom the script element will be evaluated and ran by the browser. With that being said I suppose it is possible that an extremely crafty person could exploit a bug that is present in some framework or browser you might be using to cause an undesired outcome.

Consider this example:

<p>
    <input type="button" value="Store 'The Script' In Variable" id="store"/>
    <input type="button" value="Append 'The Script' To Dom" id="append"/>
</p>
<br/>
<p>
    <input type="button" value="Does nothing"/>
</p>
<h1>The Script</h1>
<pre id="script">
    $(function(){
        function clickIt(){
            $(this).clone().click(clickIt).appendTo("body");
        }
        $("input[type="button"]").val("Now Does Something").click(clickIt);
    });
</pre>

var theScript;

$("#store").click(function() {
    theScript = document.createElement('script');
    var scriptText = document.createTextNode($("#script").text());
    theScript.appendChild(scriptText);
});

$("#append").click(function() {
    var head = document.getElementsByTagName('head')[0];
    head.appendChild(theScript);
});

When you click on store it will create the HtmlScriptElement and store it into a variable. You will notice that nothing is ran even though the object is created. As soon as you click append the script is appended to the dom and immediately evaluated and the buttons do something different.

Code Example on jsfiddle

Can any functions in javascript/jquery “watch” for elements
being created in this manner and act
on it BEFORE it’s been stripped of bad
elements and put on document?

jQuery sort of does that for you already as it does some internal script eval

From Karl Swedberg post on .append()

All of jQuery’s insertion methods use
a domManip function internally to
clean/process elements before and
after they are inserted into the DOM.
One of the things the domManip
function does is pull out any script
elements about to be inserted and run
them through an “evalScript routine”
rather than inject them with the rest
of the DOM fragment. It inserts the
scripts separately, evaluates them,
and then removes them from the DOM.

You could alter the behavior of jQuery to remove all <script/> and sanitize other elements with inline javascript onclick, mouseover, etc when calling append() however that will only affect jQuery as someone could easily use vanilla javascript to append the <script/> element.

Dom Mutation Events

Dom Level 2 does defined some Dom mutation events to capture elements that are added to the dom one would look towards the event, DOMNodeInserted. However it is fired after the element has already been added. note, per Raynos these are currently deprecated.

DOMNodeInserted Fired when a node has
been added as a child of another node.
This event is dispatched after the
insertion has taken place. The target
of this event is the node being
inserted. Bubbles: Yes Cancelable: No
Context Info: relatedNode holds the
parent node

In the end it appears there is no totally stop a <script/> being appended to the dom via some other javascript. (at least not that I can find).

The best way I can suggest is to never ever trust user input as all user input is evil. When you do dom manipulation double check to make sure there are no forbidden tags, be it <script/> or even plain <p/> elements and sanitize all input before it is persisted.

Also as John points out you need to worry about any element that can attach a onclick event or any inline javascript event handler.

Leave a Comment

Hata!: SQLSTATE[HY000] [1045] Access denied for user 'divattrend_liink'@'localhost' (using password: YES)