Skip to content
Angular ng security 4 min read

Security Overview

Unlike a minimal backend framework, Angular ships with strong, opinionated security defaults baked directly into its rendering engine. The template compiler treats all interpolated values as untrusted data, automatically escaping and sanitizing them before they reach the DOM. Understanding what Angular protects you from for free — and where you remain responsible — is the foundation for building applications that resist the everyday threats described in the OWASP Top 10. This page maps those threats to Angular’s defenses and frames the rest of this section as a single layered strategy.

Angular’s secure-by-default model

The single most important security feature in Angular is contextual auto-escaping. When you bind a value into a template, Angular knows the context — HTML body, attribute, URL, style, or resource URL — and sanitizes accordingly. A string containing markup is rendered as inert text, not parsed as HTML.

import { Component } from '@angular/core';

@Component({
  selector: 'app-comment',
  standalone: true,
  template: `<p>{{ comment }}</p>`,
})
export class CommentComponent {
  // Even if a user submitted this, the <script> is never executed
  comment = `Hello <script>alert('xss')</script>`;
}

Output (rendered DOM):

<p>Hello &lt;script&gt;alert('xss')&lt;/script&gt;</p>

The script tag appears as literal text on the page. Angular escaped the angle brackets because the value flowed into an HTML interpolation context. The same protection applies to property bindings such as [innerText] and to sanitization-aware bindings like [innerHTML], where Angular strips dangerous content rather than escaping it wholesale.

Tip: Trust Angular’s sanitizer. The vast majority of XSS bugs in Angular apps come from developers bypassing it (for example with bypassSecurityTrustHtml) rather than from gaps in the framework itself.

Mapping threats to Angular defenses

Most web threats have a corresponding Angular control. Some are automatic; others require configuration on your part.

Threat (OWASP)What it isAngular defense
Cross-Site Scripting (XSS)Malicious markup executed in the victim’s browserAutomatic contextual escaping & DOM sanitization
Cross-Site Request Forgery (CSRF)Forged state-changing requests from another siteHttpClient XSRF token interceptor + server cookie
Injection via templatesUntrusted data treated as executable HTML/URLSanitizer strips javascript: URLs, event handlers
Clickjacking / content injectionPage framed or scripts loaded from rogue originsContent-Security-Policy (configured by you)
Broken access control (A01)Acting beyond granted permissionsFunctional route guards + server-side authorization
Sensitive data exposureSecrets leaking to the client bundleKeep secrets server-side; never ship them in builds

Trusting and bypassing the sanitizer

Sometimes you genuinely need to render trusted HTML — say, sanitized rich text from your own CMS. Angular makes this explicit and auditable through the DomSanitizer, so every bypass is a visible, searchable decision in your codebase.

import { Component, inject } from '@angular/core';
import { DomSanitizer, SafeHtml } from '@angular/platform-browser';

@Component({
  selector: 'app-article',
  standalone: true,
  template: `<div [innerHTML]="safeBody"></div>`,
})
export class ArticleComponent {
  private sanitizer = inject(DomSanitizer);

  // Only do this for content you fully control and trust
  safeBody: SafeHtml = this.sanitizer.bypassSecurityTrustHtml(
    '<strong>Trusted</strong> markup from our CMS'
  );
}

Reserve bypassSecurityTrust* for values that originate from a trusted source. Passing user-supplied input through it reintroduces exactly the XSS hole Angular was protecting you from. See bypassing sanitization safely for the full guidance.

CSRF protection with HttpClient

Angular’s HttpClient has built-in CSRF (XSRF) defense. When the server sets a cookie named XSRF-TOKEN, Angular automatically reads it and echoes its value back in an X-XSRF-TOKEN header on mutating requests. Because a cross-site attacker cannot read your cookies, they cannot forge the header.

import { provideHttpClient, withXsrfConfiguration } from '@angular/common/http';
import { ApplicationConfig } from '@angular/core';

export const appConfig: ApplicationConfig = {
  providers: [
    provideHttpClient(
      withXsrfConfiguration({
        cookieName: 'XSRF-TOKEN',
        headerName: 'X-XSRF-TOKEN',
      })
    ),
  ],
};

The server must validate that the header matches the cookie before accepting any state-changing request. Details live in CSRF protection.

Access control is a server concern

Route guards improve user experience by hiding views the current user should not see, but they run in the browser and can be bypassed. They are not a security boundary.

import { inject } from '@angular/core';
import { CanActivateFn, Router } from '@angular/router';
import { AuthService } from './auth.service';

export const authGuard: CanActivateFn = () => {
  const auth = inject(AuthService);
  const router = inject(Router);
  return auth.isLoggedIn() ? true : router.createUrlTree(['/login']);
};

Warning: Never rely on a guard alone to protect data. Every API the client calls must independently authorize the request on the server. Treat the Angular bundle as fully public — anyone can read it and call your endpoints directly.

Best Practices

  • Let Angular’s interpolation and binding sanitize output automatically; do not reach for [innerHTML] unless you actually need to render markup.
  • Limit bypassSecurityTrust* calls to trusted, server-controlled content, and keep them few and reviewable.
  • Configure provideHttpClient(withXsrfConfiguration(...)) and validate the token server-side to close CSRF.
  • Deploy a strict Content-Security-Policy so injected scripts cannot execute even if an escaping gap appears.
  • Use route guards for UX, but enforce real authorization on every server endpoint.
  • Keep secrets and API keys out of the client bundle — anything shipped to the browser is public.
  • Run ng update and npm audit regularly; most breaches arrive through outdated dependencies, not framework flaws.
Last updated June 14, 2026
Was this helpful?