Posted by Ksenia Dmitrieva on August 2, 2016
If you’ve been following AngularJS security news, you’ve probably heard about “escaping the sandbox” in every other version of the framework. Recently, the same vulnerability was discovered in versions 1.5.7 and 1.5.8.
With these restrictions, all an attacker can do is execute a mathematical function, call an already existing function of the application, or display and modify data from a scope variable. This limits the impact of an Angular injection.
Although, the AngularJS documentation explicitly states that the sandbox’s purpose is to maintain a separation of application responsibilities. The sandbox isn’t available for the purpose of security. As a result, the AngularJS sandbox shouldn’t be considered a security boundary.
To try it out for yourself, create an HTML file with the following content and open it in your browser:
When running this code, you will see an alert box pop up with the word “hacked” in it. You can also test it out on https://jsfiddle.net/.
You can view a list of sandbox escape payloads for different Angular versions at the Pastebin website. Read about the technicalities of a possible attack using these payloads at the PortSwigger blog. A question that developers usually ask is “What does this mean to my application; is my AngularJS application now insecure?” The answer is: not necessarily. An AngularJS application is vulnerable to an XSS if it meets these two conditions:
Generally, data binding provided by AngularJS, by default, does not allow AngularJS code to run where data is inserted into a template. However, there are several exceptions to this case.
In such cases, they first insert user data into the template. The AngularJS code evaluates the template to perform the rest of the data binding. This often happens when developers use both server-side and client-side templates. For example, developers use JSP (when using Java) or EJS (when using Node.js) on the server-side. Additionally, within the JSP or EJS template files, they are adding AngularJS directives and some user input.
Server-side techniques for preventing XSS encode special characters like angle brackets, but will not encode curly braces which indicate an AngularJS expression. That means the AngularJS template is modified on the server-side. User data is inserted into it before it passes to the client-side. At this point, the rest of the data is inserted through Angular data binding. If the user data inserted on the server-side contains an AngularJS expression, it will now be evaluated as code on the client-side. This is the typical injection scenario: “data is evaluated as code.”
For example, a PHP code inside the HTML file can inject an AngularJS expression and inject some user input between the double curly braces. In this case, again, the code between the curly braces will be evaluated on the client-side as an AngularJS expression.
Developers should avoid mixing server-side and client-side templates as much as possible. However, this is often not a valid solution when a team is porting an old application into AngularJS. In this case, developers can limit the scope of the AngularJS app on their website. Limit the scope by only assigning the “ng-app” directive to the HTML element that must contain AngularJS code, not the whole HTML document.
Another important way to prevent AngularJS injections is a combination of thorough code review and penetration testing that looks for these types of vulnerabilities. Unfortunately, there is no silver bullet to solve this problem, like many other problems in application security. Following security best practices and security activities at every step of the software development life cycle is the only way to create better, more secure web applications.
Written in coordination with Lewis Ardern.