4

I was interested to know how AngularJS prevents inline <script> tags from executing when they are included via the ng-include directive.

After a template is included and the DOM is inspected, the script tags certainly exist, but they have not been executed. How are they being disarmed?

I have begun reviewing the source code but any attempt I have made to include a script tag into the DOM myself (appendChild, innerHTML, innerText, document.write, etc.) always results in it being executed.

Thank You.

2
  • Probably ng-sanitize is the one that is in charge of that behaviour github.com/angular/angular.js/blob/… Commented Feb 2, 2019 at 20:39
  • @charlietfl - as i mentioned the script tags are definitely still in the dom - they even have an attached ng-scope - nothing looks to have been removed Commented Feb 3, 2019 at 0:00

2 Answers 2

2

That is an artifact of the way jqLite is implemented.

To make script tags work, simply ensure that the jQuery library is loaded before the angular.js file.

  <head>
    <script src="//unpkg.com/jquery"></script>
    <script src="//unpkg.com/angular/angular.js"></script>
    <link rel="stylesheet" href="style.css">
    <script src="script.js"></script>
  </head>

The DEMO on PLNKR.


if you explain more that innerHTML is enough to prevent the script tags from executing I will select your answer as correct

HTML5 specifies that a <script> tag inserted with innerHTML should not execute.

However, there are ways to execute JavaScript without using <script> elements, so there is still a security risk whenever you use innerHTML to set strings over which you have no control. For example:

const name = "<img src='x' onerror='alert(1)'>";
el.innerHTML = name; // shows the alert

For that reason, it is recommended you not use innerHTML when inserting plain text; instead, use Node.textContent. This doesn't parse the passed content as HTML, but instead inserts it as raw text.

For more information, see MDN Web API Reference - Element.innerHTML.

Sign up to request clarification or add additional context in comments.

5 Comments

thanks @georgeawg for the answer - but my question is how is jqlite preventing the script tags from executing? not how to get the script tags to execute.
The source for jqLite.append is at GITHUB jqLite.js Line #972. It appends script elements without executing them. On the other hand, the jQuery append method recognizes script elements and executes them.
I see the append function then calls appendChild, but it must be doing more than that because appendChild always executes the script when I use it to insert a script element - how is angularjs able to use appendChild without executing the script? Can you create a working example or fiddle in plain JavaScript that works?
if you explain more that innerHTML is enough to prevent the script tags from executing I will select your answer as correct
i see you edited the question - innerHTML will execute code if it is used on a script element itself - it won’t execute code if it is used to insert the script tag and the code together - I wonder if that distinction should be made somewhere - either way - thanks for your work
0

It looks like ng-include calls $element.html(ctrl.template); See source on GitHub

The html function of jqLite then uses element.innerHTML = value; to insert the content. See source on GitHub

And after testing - it looks like that is enough to not execute <script> tags.

I've created a jsFiddle here. - #3 is the equivalent of what AngularJS is doing and it does not execute the script tags.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.