Packages / @angular/router / Security
Angular Server-Side Rendering (SSR): Denial of Service via Numeric URL Matrix Parameters
Affected releases · @angular/router
- 22.x22.0.0 – 22.1.8Fixed in 22.2.0
- 21.x21.0.0 – 21.2.23Fixed in 21.2.24
- 20.x20.0.0 – 20.3.31Fixed in 20.3.32
- 19.x19.0.0 – 19.2.25No fix on this line yet
- 18.x and older0.0.0 – 18.2.14No fix, no longer updated
On 22.x, the newest line:
npm install @angular/router@22.2.0Affected
22.0.0 – 22.1.8
18 releases
Fixed
22.2.0 – 22.2.3
4 releases, latest
Affected
21.0.0 – 21.2.23
41 releases
Fixed
21.2.24 – 21.2.25
2 releases
Affected
20.0.0 – 20.3.31
53 releases
Fixed
20.3.32 – 20.3.34
3 releases
Affected
19.0.0 – 19.2.25
43 releases
Affected
18.0.0 – 18.2.14
29 releases
Affected
17.0.0 – 17.3.12
32 releases
Affected
16.0.0 – 16.2.12
30 releases
Affected
15.0.0 – 15.2.10
22 releases
Affected
14.0.0 – 14.3.0
26 releases
Affected
13.0.0 – 13.4.0
30 releases
Affected
12.0.0 – 12.2.17
30 releases
Affected
11.0.0 – 11.2.14
28 releases
Affected
10.0.0 – 10.2.5
28 releases
Affected
9.0.0 – 9.1.13
22 releases
Affected
8.0.0 – 8.2.14
23 releases
Affected
7.0.0 – 7.2.16
27 releases
Affected
6.0.0 – 6.1.10
20 releases
Affected
5.0.0 – 5.2.11
22 releases
Affected
4.0.0 – 4.4.7
29 releases
Affected
3.0.0 – 3.4.10
24 releases
Affected
0.0.0 – 0.2.0
4 releases
Is your project affected?
Paste your package.json, or type the range you declare for @angular/router. It is read in your browser and sent nowhere.
What happens
A denial of service (DoS) vulnerability was identified in @angular/router when Server-Side Rendering (SSR) is enabled on Node.js (V8).
When @angular/router parses incoming request URLs, it extracts path segments, matrix parameters, and child outlets into plain JavaScript objects (Record<string, string>). When matrix parameter names or outlet names are numeric strings (such as /a;990;2522), the V8 JavaScript engine interprets them as array-indexed properties rather than named properties.
Under V8's internal property-storage heuristics, setting numeric keys on an initially empty object causes V8 to allocate a dense array backing store (HOLEY_ELEMENTS) sized to the maximum index rather than falling back to sparse dictionary storage. Specifically, assigning sequential or moderately large numeric keys (like 990 followed by 2522) causes V8 to allocate a contiguous backing store of ~2,522 pointers (~20 KB to 25 KB of heap) for a single 11-byte segment.
Because each segment in a URL path allocates its own independent parameters object, an attacker can craft URLs with repeated numeric matrix parameters to achieve an asymmetric memory amplification factor of approximately ~350x.
Impact
Successful exploitation allows an unauthenticated remote attacker to exhaust the Node.js old-space heap with modest request volume, terminating the SSR worker with an unrecoverable JavaScript heap out of memory fatal error and causing a Denial of Service.
High Amplification: A single 11-byte segment (
/a;990;2522) consumes ~20 KB–25 KB of V8 heap.Low Concurrency Required:
With 8 KB request paths (~740 segments, within default Nginx 8 KB buffer limits), as few as 12–22 concurrent requests crash a 256 MiB–512 MiB Node.js SSR worker.
With smaller 1 KB–2 KB request paths (~90–180 segments), a burst of ~50–100 concurrent requests achieves the same heap exhaustion.
Client-side SPAs Unaffected: Pure client-side Angular applications (Single Page Applications without SSR) are not vulnerable, as local browser memory consumption does not cross a security boundary.
Attack Preconditions & Vulnerable Configurations
An application is affected only if all of the following conditions are met:
SSR Enabled: The application runs in a Server-Side Rendering environment powered by Node.js / V8.
Direct Router Parsing: User-controlled request URLs are parsed by
@angular/routerduring SSR.No Reverse-Proxy Semicolon/Segment Filtering: Upstream reverse proxies (Nginx, Cloudflare, ALB) forward URLs containing semicolons (
;) and multiple path segments without stripping or rejecting them.
Exploit Payload Example
An attacker sends concurrent HTTP requests with repeated numeric matrix parameters:
GET /a;990;2522/a;990;2522/a;990;2522/... HTTP/1.1 Host: example.com
Even with paths under 2 KB, overlapping requests during SSR will rapidly consume the V8 heap until the process crashes.
Patches
The issue is resolved by updating @angular/router to enforce V8 dictionary elements storage (setUrlDerivedKey) for numeric URL-derived keys (index >= 32). This prevents V8 from allocating oversized contiguous array backing stores while preserving route matching, parameter values, and component input bindings.
22.2.021.2.2420.3.32
Workarounds & Mitigations
If you cannot immediately upgrade to a patched version, apply one of the following mitigations at your edge or reverse proxy:
Block or Sanitize Matrix Parameters at the Reverse Proxy:
Configure your reverse proxy (e.g., Nginx, Cloudflare, or AWS WAF) to reject or strip semicolons (;) in request paths before forwarding requests to the Angular SSR service:# Nginx example: reject requests containing matrix parameters if ($uri ~* ";") { return 400; }Enforce Strict Path Segment Limits:
Reject requests with excessive path depth (e.g., more than 20–30 segments).Increase Node.js Old Space:
Increase--max-old-space-size(e.g., to 2048 or 4096 MB) to increase the concurrency threshold required to exhaust memory, though this does not fully eliminate the vulnerability under sustained traffic.