Angular has strong built-in security features, arguably stronger than any other major frontend framework. Its template compiler sanitizes by default, its DomSanitizer provides explicit escape hatches, and its strict mode catches many security issues at build time. But defaults only help if you understand them and avoid circumventing them.
Angular's Built-In XSS Protection
Angular's template engine automatically sanitizes values interpolated into templates:
<!-- Angular escapes this automatically -->
<p>{{ userInput }}</p>
Angular sanitizes values based on context. It handles HTML, URLs, styles, and resource URLs differently. This contextual escaping is more sophisticated than React's approach.
Bypass Functions: Handle With Care
Angular provides explicit bypass methods in DomSanitizer:
import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
@Component({
template: `<div [innerHTML]="trustedHtml"></div>`
})
export class RichContentComponent {
trustedHtml: SafeHtml;
constructor(private sanitizer: DomSanitizer) {
// DANGEROUS: bypasses Angular's sanitization
this.trustedHtml = this.sanitizer.bypassSecurityTrustHtml(userContent);
}
}
Every bypassSecurityTrust* call is a potential XSS vulnerability. Audit your codebase for these calls regularly. If you must render user HTML, sanitize it with DOMPurify before bypassing Angular's sanitizer:
import DOMPurify from 'dompurify';
const clean = DOMPurify.sanitize(userContent);
this.trustedHtml = this.sanitizer.bypassSecurityTrustHtml(clean);
Template Injection
Angular compiles templates at build time (Ahead-of-Time compilation). This prevents template injection attacks where an attacker provides a malicious template string. Always use AOT compilation in production:
ng build --configuration production
Never use Compiler or dynamic template compilation with user-provided strings. The JIT compiler should never be in your production bundle.
HTTP Security
HttpClient and XSRF Protection
Angular's HttpClient includes built-in XSRF (CSRF) protection:
// app.module.ts
import { HttpClientXsrfModule } from '@angular/common/http';
@NgModule({
imports: [
HttpClientModule,
HttpClientXsrfModule.withOptions({
cookieName: 'XSRF-TOKEN',
headerName: 'X-XSRF-TOKEN',
}),
],
})
export class AppModule {}
This automatically reads the XSRF token from a cookie and adds it as a header on mutating requests.
Interceptors for Security Headers
Use HTTP interceptors to add security headers to every request:
@Injectable()
export class SecurityInterceptor implements HttpInterceptor {
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const secureReq = req.clone({
setHeaders: {
'X-Requested-With': 'XMLHttpRequest',
},
});
return next.handle(secureReq);
}
}
Content Security Policy
Angular applications need careful CSP configuration. AOT-compiled Angular does not use eval(), so you can avoid 'unsafe-eval':
Content-Security-Policy:
default-src 'self';
script-src 'self';
style-src 'self' 'unsafe-inline';
img-src 'self' data: https:;
font-src 'self';
connect-src 'self' https://api.yourapp.com;
If you use Angular's built-in styles (component styles), you may need 'unsafe-inline' for style-src. Work toward nonce-based CSP to eliminate this.
Route Guards Are Not Security
Angular route guards (CanActivate, CanLoad) are UX features, not security controls:
@Injectable()
export class AdminGuard implements CanActivate {
canActivate(): boolean {
return this.authService.isAdmin();
}
}
A determined attacker can bypass client-side route guards. Every protected resource must be authorized on the server.
Strict Mode
Angular's strict mode (--strict flag when creating a project) enables stricter TypeScript and Angular compiler checks:
ng new my-app --strict
This enables:
strictTemplates- Catches template type errorsstrictInjectionParameters- Requires explicit injection metadatanoImplicitAny- No implicit any types
Use strict mode for all new projects. Migrate existing projects incrementally.
Dependency Security
Angular projects use npm. The framework has a large dependency tree (RxJS, Zone.js, TypeScript, and numerous @angular/* packages). Keep Angular updated. The Angular team releases security patches regularly, and Angular versions reach end-of-life on a predictable schedule.
# Check for outdated Angular packages
ng update
# Audit dependencies
npm audit --audit-level=high
Generate an SBOM:
npx @cyclonedx/cyclonedx-npm --output-file sbom.json
Security Checklist
- [ ] AOT compilation enabled in production
- [ ] No
bypassSecurityTrust*calls with unsanitized input - [ ] CSP headers configured without
'unsafe-eval' - [ ] XSRF protection configured in HttpClient
- [ ] All API endpoints validate auth server-side
- [ ] Strict mode enabled
- [ ]
npm auditrunning in CI - [ ] Dependencies pinned in
package-lock.json - [ ] No secrets in environment files shipped to client
- [ ] Route guards backed by server-side authorization
How Safeguard.sh Helps
Safeguard.sh tracks the full dependency tree of your Angular applications, including the Angular framework packages themselves. It monitors for CVEs across your @angular/* packages, RxJS, Zone.js, and every other dependency. For organizations with multiple Angular applications, Safeguard.sh provides a consolidated view showing which apps are on supported Angular versions and which need framework upgrades, helping your team stay ahead of both dependency vulnerabilities and framework end-of-life.