The Synopsys Software Integrity Group is now Black Duck®. Learn More

close search bar

Sorry, not available in this language yet

close language selection

AngularJS: Preventing common vulnerabilities in the MEAN stack

Black Duck Editorial Staff

May 08, 2017 / 5 min read

Before jumping into the latest post in our discussion of vulnerabilities in the MEAN stack, look back at the first three posts on MongoDBExpressJS (Core), and ExpressJS (Sessions and CSRF).

AngularJS disabled SCE service

Angular 1.2 and greater include the built-in strict contextual escaping service ($sce) by default. This service strips malicious HTML tags (e.g., <script>), attributes (e.g., onmouseover, onerror), and URI protocols (e.g., javascript) from data rendered as HTML with the ng-bind-html directive. This service can be disabled globally with the $sceProvider.enabled() method in the controller’s config block or per instance with the $sce.trustAs methods. But doing so leaves the application vulnerable to cross-site scripting (XSS) attacks when binding untrusted data as HTML.

Consider the excerpt below from our example application where the $sce service is disabled and the untrusted user input is rendered with the ng-bind-html directive.

AngularJS Logo Illustrating Software Security Against Vulnerabilities

If we submit the payload <img src=x onerror=alert('XSS_SUCCESS!')></img>, we can generate an XSS exploit.

AngularJS 2 Code Illustrating XSS Exploit with SCE Disabled

                                                                          XSS exploit with SCE disabled

The simplest solution is to leave the $sce service enabled for all untrusted input bound to the ng-bind-html directive. Removing the $sceProvider.enabled(false) method from the excerpt above means the malicious onerror attribute will be sanitized appropriately.

AngularJS Logo for Software Security Blog Post on Synopsys

                                           SCE strips malicious onerror attribute and prevents XSS exploit

Alternatively, the data could also be rendered with the ng-bind directive, which renders the text outside of the HTML context and performs HTML encoding on all malicious characters, such as angle brackets (<>) or double quotes (").

AngularJS expression injection

Angular templates (defined by the ng-app directive) use double curly braces ({{}}) to denote expressions that are evaluated by the Angular rendering engine. If an attacker can inject curly braces into the template, they can easily enter the code execution context. To further complicate matters, off-the-shelf HTML encoding or sanitizing functions do not handle curly braces.

Consider the login page for the example MEAN Bug application, which reflects the username during a failed login attempt.

AngularJS Logo with Code Snippet Background

                                                                  Username reflected in message

If we examine the source code, we see that the message is rendered as a text attribute, encoding all HTML control characters.

AngularJS Logo with Security Shield Illustrating Software Security

If we attempt the following payload, we see that the <script> tags are encoded and the exploit does not work.

http://localhost:9000/login?user=<script>alert('XSS_SUCCESS!')</script>

AngularJS Logo with HTML Encoding for XSS Prevention

                                                       HTML characters encoded to prevent XSS

However, because the text is rendered within an HTML element bound by the ng-app directive, anything encapsulated by double curly braces will be evaluated as an Angular expression. If we submit the following request, we can enter a code execution context within an Angular expression.

http://localhost:9000/login?user={{constructor.constructor('alert("XSS_SUCCESS!")')()}}

This request also contains a sandbox-escaping payload (i.e., constructor.constructor()), which allows us to break out of the Angular scope and do things like generate an alert message.

AngularJS Logo with Code Snippet Illustrating XSS Injection

                                                     Angular expression injection used to execute XSS

RELATEDBreak out of the Angular sandbox

You can remediate this vulnerability by sanitizing curly braces from untrusted input. You can also prevent the input from being written inside an Angular template by reducing the scope of the ng-app directive (e.g., bind ng-app to a div or table element rather than the body element).

Alternatively, the ng-non-bindable directive can be used to tell the rendering engine to ignore any expressions within that element. The example application has been modified with this solution to prevent the expression-injection exploit from executing.

AngularJS Logo with Shield Symbolizing Software Security
AngularJS Logo with Directive ng-non-bindable Highlighted for Software Security

                                   Directive ng-non-bindable used to prevent expression injection

AngularJS local storage information leakage

Angular’s angular-storage service allows applications to easily persist data client-side in web storage without the size restrictions imposed by cookies. However, this service defaults to using local storage, which persists indefinitely unless it is explicitly cleared. This data will remain on the user’s file system even after the browser is closed, exposing the data to any user with physical access to the system. The excerpt below demonstrates how the angular-storage service is used in its default configuration.

AngularJS Logo with Text Highlighting MEAN Stack Security

The data persisted by the angular-storage method store.set is in the browser’s local storage.

AngularJS Logo Representing Software Security

                                          Sensitive data stored in local storage will persist indefinitely

Because any client-side data is inherently insecure, local storage should not be used to persist sensitive data such as credentials or credit card numbers. A slightly more secure alternative is to configure the angular-storage service to use session storage, which is cleared automatically when the browser tab is closed. This can be done with the storeProvider service within the config block as shown below.

AngularJS Logo with Text Highlighting Software Security
AngularJS Logo for Software Security Blog Post

                                                 Application configured to use session storage

This example uses the angular-storage module, but keep in mind that data may also be persisted to local storage (and session storage) via other Angular modules such as ngStorage and angular-locker or by calling $window.localStorage or $window.sessionStorage directly.

READ NEXT: Node.js: Preventing common vulnerabilities in the MEAN stack

Continue Reading

Explore Topics