@angular/platform-server: Open Redirect via Protocol-Relative URLs in Server-Side Rendering (SSR)
An open redirect vulnerability was identified in `@angular/platform-server` when Server-Side Rendering (SSR) is enabled. When Angular SSR renders an incoming request, URL resolution and platform navigation are managed by `ServerPlatformLocation` using `resolveUrl` (or `parseUrl` in v20). While `resolveUrl` rejected protocol-relative URLs whose raw string directly started with `//`, this check ran *prior* to WHATWG URL normalization. When a request URL includes a popping dot-segment followed by multiple slashes (such as `/.//evil.test` or serialized from router route shapes like `/.;/(//evil.test)`), the input bypassed the initial `urlStr.startsWith('//')` check. Subsequent WHATWG URL parsing resolved the dot-segments and resulted in a `pathname` starting with `//` (`//evil.test`). Consequently, `ServerPlatformLocation` stored `pathname = '//evil.test'`. When `@angular/ssr` detected a mismatch between the rendered URL and the router's final location state, it emitted the unnormalized pathname into the HTTP `Location` response header, producing an HTTP 302 redirect with `Location: //evil.test`, which browsers resolve as a protocol-relative navigation off-origin. ### Impact Successful exploitation allows an unauthenticated remote attacker to craft URLs that trick Angular SSR into redirecting users to an arbitrary external domain. * **Bypasses Application-Level Guards:** Common application-level validation routines (such as checking `!returnUrl.startsWith('//')` before invoking `
- Products
- @angular/platform-server
- Affected versions
- Not specified
- Fixed versions
- 20.3.33, 21.2.25, 22.2.1
- CVEs
- CVE-2026-111754
- Confirmed fixed CVEs
- Not specified
- Updated in this feed
- 31 Oct 2026, 13:03 UTC · Revision 1
Source evidence
@angular/platform-server: Open Redirect via Protocol-Relative URLs in Server-Side Rendering (SSR)
core-osv · Original sourcePublished 20 Oct 2026, 14:35 UTC
An open redirect vulnerability was identified in `@angular/platform-server` when Server-Side Rendering (SSR) is enabled. When Angular SSR renders an incoming request, URL resolution and platform navigation are managed by `ServerPlatformLocation` using `resolveUrl` (or `parseUrl` in v20). While `resolveUrl` rejected protocol-relative URLs whose raw string directly started with `//`, this check ran *prior* to WHATWG URL normalization. When a request URL includes a popping dot-segment followed by multiple slashes (such as `/.//evil.test` or serialized from router route shapes like `/.;/(//evil.test)`), the input bypassed the initial `urlStr.startsWith('//')` check. Subsequent WHATWG URL parsing resolved the dot-segments and resulted in a `pathname` starting with `//` (`//evil.test`). Consequently, `ServerPlatformLocation` stored `pathname = '//evil.test'`. When `@angular/ssr` detected a mismatch between the rendered URL and the router's final location state, it emitted the unnormalized pathname into the HTTP `Location` response header, producing an HTTP 302 redirect with `Location: //evil.test`, which browsers resolve as a protocol-relative navigation off-origin. ### Impact Successful exploitation allows an unauthenticated remote attacker to craft URLs that trick Angular SSR into redirecting users to an arbitrary external domain. * **Bypasses Application-Level Guards:** Common application-level validation routines (such as checking `!returnUrl.startsWith('//')` before invoking `
osv:GHSA-w739-gvwx-grc3
@angular/platform-server
Fixed versions: 22.2.1
@angular/platform-server
Fixed versions: 21.2.25
@angular/platform-server
Fixed versions: 20.3.33
@angular/platform-server
Fixed versions: Not specified
Complete source record
{
"id": "65cc97022647007b0d846e84d50729ae2611f518c0ea49c6e472af6653e19828",
"url": "https://osv.dev/vulnerability/GHSA-w739-gvwx-grc3",
"method": "structured",
"payload": {
"kind": "advisory",
"title": "@angular/platform-server: Open Redirect via Protocol-Relative URLs in Server-Side Rendering (SSR)",
"summary": "An open redirect vulnerability was identified in `@angular/platform-server` when Server-Side Rendering (SSR) is enabled. When Angular SSR renders an incoming request, URL resolution and platform navigation are managed by `ServerPlatformLocation` using `resolveUrl` (or `parseUrl` in v20). While `resolveUrl` rejected protocol-relative URLs whose raw string directly started with `//`, this check ran *prior* to WHATWG URL normalization. When a request URL includes a popping dot-segment followed by multiple slashes (such as `/.//evil.test` or serialized from router route shapes like `/.;/(//evil.test)`), the input bypassed the initial `urlStr.startsWith('//')` check. Subsequent WHATWG URL parsing resolved the dot-segments and resulted in a `pathname` starting with `//` (`//evil.test`). Consequently, `ServerPlatformLocation` stored `pathname = '//evil.test'`. When `@angular/ssr` detected a mismatch between the rendered URL and the router's final location state, it emitted the unnormalized pathname into the HTTP `Location` response header, producing an HTTP 302 redirect with `Location: //evil.test`, which browsers resolve as a protocol-relative navigation off-origin. ### Impact Successful exploitation allows an unauthenticated remote attacker to craft URLs that trick Angular SSR into redirecting users to an arbitrary external domain. * **Bypasses Application-Level Guards:** Common application-level validation routines (such as checking `!returnUrl.startsWith('//')` before invoking `",
"evidence": "osv:GHSA-w739-gvwx-grc3",
"products": [
{
"name": {
"value": "@angular/platform-server",
"evidence": "/affected/0/package/name"
},
"prerequisites": [],
"fixed_versions": [
{
"value": "22.2.1",
"evidence": "/affected/0/ranges"
}
],
"affected_versions": []
},
{
"name": {
"value": "@angular/platform-server",
"evidence": "/affected/1/package/name"
},
"prerequisites": [],
"fixed_versions": [
{
"value": "21.2.25",
"evidence": "/affected/1/ranges"
}
],
"affected_versions": []
},
{
"name": {
"value": "@angular/platform-server",
"evidence": "/affected/2/package/name"
},
"prerequisites": [],
"fixed_versions": [
{
"value": "20.3.33",
"evidence": "/affected/2/ranges"
}
],
"affected_versions": []
},
{
"name": {
"value": "@angular/platform-server",
"evidence": "/affected/3/package/name"
},
"prerequisites": [],
"fixed_versions": [],
"affected_versions": []
}
],
"severity": "medium",
"structured": {
"id": "GHSA-w739-gvwx-grc3",
"aliases": [
"CVE-2026-111754",
"GHSA-w739-gvwx-grc3"
],
"metrics": [
{
"type": "CVSS_V4",
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:A/VC:N/VI:N/VA:N/SC:L/SI:L/SA:N"
}
],
"affected": [
{
"ranges": [
{
"type": "SEMVER",
"events": [
{
"introduced": "22.0.0"
},
{
"fixed": "22.2.1"
}
]
}
],
"package": {
"name": "@angular/platform-server",
"purl": "pkg:npm/%40angular/platform-server",
"ecosystem": "npm"
},
"database_specific": {
"source": "https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/10/GHSA-w739-gvwx-grc3/GHSA-w739-gvwx-grc3.json"
}
},
{
"ranges": [
{
"type": "SEMVER",
"events": [
{
"introduced": "21.0.0"
},
{
"fixed": "21.2.25"
}
]
}
],
"package": {
"name": "@angular/platform-server",
"purl": "pkg:npm/%40angular/platform-server",
"ecosystem": "npm"
},
"database_specific": {
"source": "https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/10/GHSA-w739-gvwx-grc3/GHSA-w739-gvwx-grc3.json"
}
},
{
"ranges": [
{
"type": "SEMVER",
"events": [
{
"introduced": "20.0.0"
},
{
"fixed": "20.3.33"
}
]
}
],
"package": {
"name": "@angular/platform-server",
"purl": "pkg:npm/%40angular/platform-server",
"ecosystem": "npm"
},
"database_specific": {
"source": "https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/10/GHSA-w739-gvwx-grc3/GHSA-w739-gvwx-grc3.json"
}
},
{
"ranges": [
{
"type": "SEMVER",
"events": [
{
"introduced": "0"
},
{
"last_affected": "19.2.25"
}
]
}
],
"package": {
"name": "@angular/platform-server",
"purl": "pkg:npm/%40angular/platform-server",
"ecosystem": "npm"
},
"database_specific": {
"source": "https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/10/GHSA-w739-gvwx-grc3/GHSA-w739-gvwx-grc3.json"
}
}
],
"modified": "2026-10-20T14:45:03.771349618Z",
"provider": "osv",
"references": [
"https://github.com/angular/angular/security/advisories/GHSA-w739-gvwx-grc3",
"https://github.com/angular/angular/pull/71077",
"https://github.com/angular/angular/pull/71078",
"https://github.com/angular/angular/pull/71079",
"https://github.com/angular/angular/commit/450af9c813c7660b9bd91e5635f705ee3ed7b32a",
"https://github.com/angular/angular/commit/83944fc8c50e86be90e8ec4184cd15002b5af262",
"https://github.com/angular/angular/commit/928dcfd2582152655b5559509d057bf6a5a19521",
"https://github.com/angular/angular/commit/d7d81e189d227108c3b9d39178dbb7389f6f970d",
"https://github.com/angular/angular",
"https://github.com/angular/angular/releases/tag/v20.3.33",
"https://github.com/angular/angular/releases/tag/v21.2.25",
"https://github.com/angular/angular/releases/tag/v22.2.1"
],
"provider_metadata": {
"cwe_ids": [
"CWE-601"
],
"severity": "MODERATE",
"github_reviewed": true,
"nvd_published_at": null,
"github_reviewed_at": "2026-10-20T14:35:49Z"
}
},
"related_cves": [
{
"value": "CVE-2026-111754",
"evidence": "/aliases"
}
],
"security_relevant": true,
"severity_evidence": "/severity/0/score"
},
"source_id": "core-osv",
"document_id": 389728,
"published_at": "2026-10-20T14:35:49+00:00"
}