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:
- Understanding XSS and Its Impact
- Built-in AngularJS Protections Against XSS
- Using
$sce
(Strict Contextual Escaping) to Prevent XSS - Sanitizing User Input Using
$sanitize
- Avoiding
ng-bind-html
Without Proper Sanitization - 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><script>alert('XSS');</script></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.