Preventing Cross-Site Scripting (XSS) in AngularJS

Loading

Cross-Site Scripting (XSS) is a common web security vulnerability that allows attackers to inject malicious scripts into web pages. In AngularJS, XSS can occur if user input is not properly sanitized before being rendered in the DOM.

This guide covers:

  1. Understanding XSS and Its Impact
  2. Built-in AngularJS Protections Against XSS
  3. Using $sce (Strict Contextual Escaping) to Prevent XSS
  4. Sanitizing User Input Using $sanitize
  5. Avoiding ng-bind-html Without Proper Sanitization
  6. Best Practices to Prevent XSS in AngularJS

1. Understanding XSS and Its Impact

XSS attacks allow attackers to execute JavaScript in a victim’s browser. These attacks can:

  • Steal user session cookies.
  • Redirect users to malicious sites.
  • Deface web pages.
  • Perform actions on behalf of the user.

Example of an XSS Attack

An attacker injects a malicious script into an input field:

<input type="text" ng-model="userInput">
<div ng-bind-html="userInput"></div>

If a user enters:

<script>alert('Hacked!');</script>

It will execute when the page is rendered.


2. Built-in AngularJS Protections Against XSS

AngularJS automatically sanitizes and escapes potentially dangerous content in most cases. It provides: ✔ Auto-escaping in expressions ({{ }})
Contextual auto-escaping for attributes (e.g., href, src)
Strict Contextual Escaping ($sce) for potentially unsafe values

Safe Example

<div>{{ userInput }}</div>

If userInput contains <script>alert('XSS');</script>, AngularJS escapes it:

<div>&lt;script&gt;alert('XSS');&lt;/script&gt;</div>

This prevents script execution.


3. Using $sce (Strict Contextual Escaping) to Prevent XSS

AngularJS provides the $sce service to mark trusted content explicitly. This prevents untrusted content from being injected into ng-bind-html or iframe src.

Example: Trusting a URL in an iframe

app.controller('MainController', function($scope, $sce) {
$scope.safeUrl = $sce.trustAsResourceUrl('https://example.com');
});
<iframe ng-src="{{ safeUrl }}"></iframe>

If an attacker tries to inject an untrusted URL, $sce will block it.

Marking Safe HTML for ng-bind-html

$scope.safeHTML = $sce.trustAsHtml('<b>Safe HTML</b>');
<div ng-bind-html="safeHTML"></div>

Warning: Only use $sce.trustAsHtml() for known safe content. Otherwise, sanitize user input first.


4. Sanitizing User Input Using $sanitize

If you need to display HTML content but want to remove unsafe elements (<script>, <iframe>, etc.), use the $sanitize service.

Install angular-sanitize

First, include the angular-sanitize module:

<script src="angular-sanitize.js"></script>

Add it to your app:

var app = angular.module('myApp', ['ngSanitize']);

Using $sanitize in a Controller

app.controller('MainController', function($scope, $sanitize) {
var unsafeInput = '<script>alert("Hacked!");</script><b>Bold Text</b>';
$scope.safeContent = $sanitize(unsafeInput);
});
<div ng-bind-html="safeContent"></div>

Result: The <script> tag is removed, but <b>Bold Text</b> remains.


5. Avoiding ng-bind-html Without Proper Sanitization

Avoid using ng-bind-html with untrusted input unless it has been sanitized.

Unsafe Example

<div ng-bind-html="userInput"></div>

This renders raw HTML and allows script execution.

Safe Approach

<div ng-bind-html="sanitizedContent"></div>

Where sanitizedContent is processed with $sanitize.


6. Best Practices to Prevent XSS in AngularJS

Always use AngularJS’s built-in auto-escaping (via {{ }}).
Sanitize user-generated HTML using $sanitize.
Use $sce cautiously to mark trusted content only when necessary.
Avoid inline event handlers (onclick="...", onerror="...").
Validate and sanitize user input before storing it in a database.
Set HTTP security headers (e.g., Content Security Policy (CSP)).
Use ng-src instead of src for images to prevent attribute injection.

Leave a Reply

Your email address will not be published. Required fields are marked *