[$sce:unsafe] Unsafe content blocked by AngularJS

Loading

In AngularJS, Strict Contextual Escaping (SCE) is a security feature that helps prevent Cross-Site Scripting (XSS) attacks by blocking potentially unsafe content. When AngularJS detects unsafe content, it throws the error:

[$sce:unsafe] Attempting to use an unsafe value in a safe context.

This happens when you try to bind HTML, URLs, or JavaScript that Angular considers unsafe. This guide will explain why this happens, how to fix it securely, and how to prevent XSS vulnerabilities.


1. Why Does AngularJS Block Unsafe Content?

AngularJS blocks unsafe content to prevent attackers from injecting malicious scripts into the application.

1️⃣ Example of Unsafe Content in AngularJS

Consider the following example where we use ng-bind-html:

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

If userInput contains:

$scope.userInput = "<script>alert('XSS Attack!');</script>";

The browser blocks this content due to AngularJS’s SCE protection.

2️⃣ Common Causes of [$sce:unsafe] Errors

  • Using ng-bind-html with untrusted content
  • Displaying untrusted URLs in src or href attributes
  • Using JavaScript URLs (e.g., javascript:alert(1))
  • Trying to load iframe content with ng-src

2. Fixing [$sce:unsafe] Error Securely

If you trust the content, you can mark it as safe using $sce.trustAsHtml().

1️⃣ Using $sce.trustAsHtml() for Safe HTML

app.controller("MyCtrl", function ($scope, $sce) {
$scope.safeHtml = $sce.trustAsHtml("<b>This is safe HTML</b>");
});
<div ng-bind-html="safeHtml"></div>

This works, but should only be used for trusted content.

Warning: Do NOT use $sce.trustAsHtml() on user-generated content, as it can introduce XSS vulnerabilities.


2️⃣ Using $sce.trustAsResourceUrl() for URLs

If you need to use a dynamic URL (e.g., an iframe src), Angular blocks it unless it is explicitly trusted.

$scope.trustedUrl = $sce.trustAsResourceUrl("https://example.com");
<iframe ng-src="{{trustedUrl}}"></iframe>

Use this only for trusted sources.


3️⃣ Using $sce.trustAsJs() for JavaScript URLs (Not Recommended)

If you are trying to load a javascript: URL (e.g., javascript:alert(1);), Angular blocks it.

$scope.trustedJs = $sce.trustAsJs("javascript:alert('XSS');");

This is dangerous and should be avoided.
Instead, use event handlers in JavaScript.


3. Preventing XSS When Using $sce

To safely handle HTML content, follow best security practices:

1. Use a Sanitization Library

Instead of blindly trusting content, sanitize it before displaying:

app.controller("MyCtrl", function ($scope, $sanitize) {
$scope.safeContent = $sanitize(userInput);
});
<div ng-bind-html="safeContent"></div>

This removes malicious scripts while keeping safe HTML elements.


2. Validate and Escape User Input

If your application accepts user input, always validate and escape it before rendering.

Sanitize on the Backend (Example in Node.js)

const sanitizeHtml = require('sanitize-html');
let cleanInput = sanitizeHtml(userInput);

Use encodeURIComponent() for URLs

let safeUrl = encodeURIComponent(userProvidedUrl);

3. Use a Content Security Policy (CSP)

Adding a CSP header can block inline scripts and unsafe URLs:

Content-Security-Policy: default-src 'self'; script-src 'self'

This prevents malicious scripts from executing.


4. Summary

IssueSecure Fix
$sce:unsafe error when using ng-bind-htmlUse $sce.trustAsHtml() only for trusted content
Unsafe iframe ng-srcUse $sce.trustAsResourceUrl()
XSS attack via user inputSanitize input using $sanitize or backend validation
Allowing JavaScript URLsAvoid javascript: URLs and use event listeners instead

Security Best Practices:

Always sanitize user input
Avoid $sce.trustAsHtml() for untrusted content
Use CSP headers to block XSS attacks
Validate all URLs before rendering

Leave a Reply

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