Skip to main content

Security Best Practices

Angular has built-in protections against common web application vulnerabilities and attacks such as cross-site scripting (XSS). This guide covers Angular’s security features and best practices to keep your applications secure.
This guide focuses on Angular’s built-in security features. It does not cover application-level security such as authentication, authorization, or server-side security.

General Security Guidelines

Keep Angular Updated

Regular updates include security fixes. Check the Angular changelog for security-related updates.

Don't Modify Angular

Private, customized versions fall behind and miss security fixes. Contribute improvements to the community instead.

Avoid Risky APIs

APIs marked “Security Risk” in documentation should be used with extreme caution.

Preventing Cross-Site Scripting (XSS)

Cross-site scripting (XSS) enables attackers to inject malicious code into web pages. This is one of the most common attacks on the web.

Angular’s XSS Security Model

Angular treats all values as untrusted by default. When a value is inserted into the DOM from a template binding or interpolation, Angular sanitizes and escapes untrusted values.
import { Component } from '@angular/core';

@Component({
  selector: 'app-inner-html-binding',
  template: `
    <!-- Interpolation - Always escaped -->
    <p>{{ htmlSnippet }}</p>
    
    <!-- innerHTML binding - Sanitized -->
    <div [innerHTML]="htmlSnippet"></div>
  `
})
export class InnerHtmlBindingComponent {
  // Angular automatically sanitizes dangerous content
  htmlSnippet = '<b>Bold text</b><script>alert("XSS")</script>';
  // Result: <b>Bold text</b> (script tag removed)
}

Security Contexts

Angular defines different security contexts, each with specific sanitization rules:
Used when interpreting a value as HTML, such as binding to innerHTML.
@Component({
  template: `<div [innerHTML]="userContent"></div>`
})
export class MyComponent {
  userContent = '<b>Safe</b><script>unsafe()</script>';
  // Result: <b>Safe</b> (script removed)
}

Sanitization and Trusted Values

Direct DOM Manipulation

When using DOM APIs directly, you must manually sanitize untrusted values:
import { Component, inject, ElementRef, viewChild, signal } from '@angular/core';
import { DomSanitizer, SecurityContext } from '@angular/platform-browser';

@Component({
  selector: 'app-manual-sanitization',
  template: `
    <div #container></div>
    <button (click)="addContent()">Add Content</button>
  `
})
export class ManualSanitizationComponent {
  private sanitizer = inject(DomSanitizer);
  private container = viewChild.required<ElementRef>('container');
  
  userContent = signal('<b>User content</b><script>alert("XSS")</script>');
  
  addContent() {
    const sanitized = this.sanitizer.sanitize(
      SecurityContext.HTML,
      this.userContent()
    );
    
    if (sanitized) {
      this.container().nativeElement.innerHTML = sanitized;
      // Result: <b>User content</b> (script removed)
    }
  }
}
Never use DOM APIs like innerHTML, outerHTML, document.write(), or Element.setAttribute() with untrusted data without sanitization.

Trusting Safe Values

Sometimes applications genuinely need to include executable code or construct potentially dangerous URLs. Use DomSanitizer methods to mark values as trusted:
import { Component, inject } from '@angular/core';
import { DomSanitizer, SafeUrl } from '@angular/platform-browser';

@Component({
  selector: 'app-bypass-security',
  template: `
    <!-- This would normally be sanitized -->
    <a [href]="dangerousUrl">Click me</a>
  `
})
export class BypassSecurityComponent {
  private sanitizer = inject(DomSanitizer);
  
  // Mark the URL as trusted
  dangerousUrl: SafeUrl = this.sanitizer.bypassSecurityTrustUrl('javascript:void(0)');
}
Be extremely careful when bypassing security. If you trust a malicious value, you introduce a security vulnerability. When in doubt, consult a security expert.

Content Security Policy (CSP)

Content Security Policy is a defense-in-depth technique to prevent XSS. Configure your web server to return an appropriate Content-Security-Policy HTTP header.

Minimal CSP Configuration

The minimal policy required for a new Angular application:
Content-Security-Policy: default-src 'self'; style-src 'self' 'nonce-randomNonceGoesHere'; script-src 'self' 'nonce-randomNonceGoesHere';
angular.json
{
  "projects": {
    "my-app": {
      "architect": {
        "build": {
          "options": {
            "autoCsp": true
          }
        }
      }
    }
  }
}
Critical: Always ensure that nonces are unique per request and not predictable. If an attacker can predict future nonces, they can circumvent CSP protections.

CSP Policy Breakdown

Allows the page to load all required resources from the same origin. This is the baseline security policy.
Allows the page to:
  • Load global styles from the same origin ('self')
  • Load styles inserted by Angular with the specified nonce
Allows the page to:
  • Load JavaScript from the same origin ('self')
  • Load scripts inserted by Angular CLI with the specified nonce
  • Required if using critical CSS inlining

Trusted Types

Trusted Types is a web platform feature that helps prevent XSS by enforcing safer coding practices. It’s recommended to use Trusted Types with Angular.

Configuring Trusted Types

Configure HTTP headers with Angular policies:
Content-Security-Policy: trusted-types angular; require-trusted-types-for 'script';

Angular Trusted Type Policies

angular

Required for all appsUsed in security-reviewed code internal to Angular. Any inline template values or content sanitized by Angular is treated as safe.

angular#bundler

For lazy loadingUsed by Angular CLI bundler when creating lazy chunk files.

angular#unsafe-bypass

For DomSanitizer bypassRequired if using bypassSecurityTrustHtml, bypassSecurityTrustScript, etc.

angular#unsafe-jit

For JIT compilationRequired if using JIT compiler or platform browser dynamic.

AOT Template Compiler

The Ahead-of-Time (AOT) template compiler prevents template injection vulnerabilities and greatly improves performance.
// Templates are compiled at build time
@Component({
  selector: 'app-user-greeting',
  template: `<h1>Hello {{ userName }}</h1>`
})
export class UserGreetingComponent {
  userName = 'John';
}
// Template is pre-compiled and type-checked
Never create Angular templates on the server side or dynamically generate templates with user data. This carries a high risk of template injection vulnerabilities.

HTTP Security

XSRF/CSRF Protection

Angular’s HttpClient has built-in protection against Cross-Site Request Forgery (XSRF/CSRF) attacks:
import { ApplicationConfig } from '@angular/core';
import { provideHttpClient } from '@angular/common/http';

export const appConfig: ApplicationConfig = {
  providers: [
    provideHttpClient()
    // XSRF protection is enabled by default
    // Reads token from 'XSRF-TOKEN' cookie
    // Sends token in 'X-XSRF-TOKEN' header
  ]
};

How XSRF Protection Works

1

Server Sets Cookie

Server sets a token in a JavaScript-readable cookie called XSRF-TOKEN on page load or first GET request
2

Client Reads Cookie

Angular’s HttpClient reads the token from the cookie
3

Client Sends Header

On mutating requests (POST, PUT, DELETE), the interceptor adds an X-XSRF-TOKEN header with the token value
4

Server Verifies

Server verifies that the cookie matches the header value, ensuring the request came from your application
Why this works: Only code from your domain can read the cookie and set the header. Malicious sites cannot access cookies from other domains due to the same-origin policy.

XSSI Protection

Angular automatically protects against Cross-Site Script Inclusion (XSSI) attacks:
// Server response
")]}',\n{\"user\": \"John\", \"role\": \"admin\"}"

// Angular automatically strips the prefix
this.http.get<User>('/api/user').subscribe(user => {
  console.log(user);  // { user: "John", role: "admin" }
});

Server-Side Request Forgery (SSRF) Prevention

Angular includes strict validation for headers to prevent SSRF attacks:
{
  "projects": {
    "my-app": {
      "architect": {
        "build": {
          "options": {
            "security": {
              "allowedHosts": [
                "example.com",
                "*.example.com",
                "api.trusted-service.com"
              ]
            }
          }
        }
      }
    }
  }
}

Validated Headers

Validated against a strict allowlist. Cannot contain path separators. Unrecognized hostnames result in CSR page or 400 Bad Request.
Must be numeric. Non-numeric values are rejected.
Must be http or https. Other values are rejected.
Must not start with multiple / or \\ and cannot contain . or .. path segments.

Security Checklist

  • Keep Angular updated to the latest stable version
  • Review security advisories in Angular changelog
  • Never modify Angular’s core files
  • Audit all uses of security-sensitive APIs
  • Use AOT compilation in production (enabled by default)
  • Never use innerHTML with untrusted data
  • Sanitize data when using DOM APIs directly
  • Only bypass security when absolutely necessary
  • Document why security is bypassed for each case
  • Avoid dynamically generating templates
  • Implement Content Security Policy headers
  • Use unique, unpredictable nonces per request
  • Enable Trusted Types enforcement
  • Include appropriate Angular policies
  • Test CSP in development and staging
  • Ensure XSRF protection is enabled (default)
  • Configure custom XSRF cookies if needed
  • Validate all user input on the server
  • Use HTTPS in production
  • Configure allowed hosts for SSR

Common Vulnerabilities to Avoid

Template Injection

// ❌ Never do this
const template = `<div>${userInput}</div>`;
Use data binding instead of string concatenation

Unsafe DOM Access

// ❌ Avoid direct DOM manipulation
element.innerHTML = userContent;
Use Angular’s sanitizer when necessary

Eval and Function Constructor

// ❌ Never use eval with user data
eval(userInput);
new Function(userInput)();
These execute arbitrary code

Unsafe Resource URLs

// ❌ Don't trust user-provided URLs
<iframe [src]="userUrl">
Always validate and sanitize URLs

Reporting Security Vulnerabilities

If you discover a security vulnerability in Angular, please report it responsibly:

Next Steps

Continue learning about Angular best practices: