{"id":"GHSA-xh43-g2fq-wjrj","summary":"Angular SSR has an Open Redirect via X-Forwarded-Prefix","details":"An Open Redirect vulnerability exists in the internal URL processing logic in Angular SSR. The logic normalizes URL segments by stripping leading slashes; however, it only removes a single leading slash.\n\nWhen an Angular SSR application is deployed behind a proxy that passes the `X-Forwarded-Prefix` header, an attacker can provide a value starting with three slashes (e.g., `///evil.com`).\n\n1. The application processes a redirect (e.g., from a router `redirectTo` or i18n locale switch).\n2. Angular receives `///evil.com` as the prefix.\n3. It strips one slash, leaving `//evil.com`.\n4. The resulting string is used in the `Location` header.\n5. Modern browsers interpret `//` as a protocol-relative URL, redirecting the user from `https://your-app.com` to `https://evil.com`.\n\n\n### Impact\nThis vulnerability allows attackers to conduct large-scale phishing and SEO hijacking:\n- **Scale:** A single request can poison a high-traffic route, impacting all users until the cache expires.\n- **SEO Poisoning:** Search engine crawlers may follow and index these malicious redirects, causing the legitimate site to be delisted or associated with malicious domains.\n- **Trust:** Because the initial URL belongs to the trusted domain, users and security tools are less likely to flag the redirect as malicious.\n\n### Attack Preconditions\n\n- The application must use Angular SSR.\n- The application must have routes that perform internal redirects.\n- The infrastructure (Reverse Proxy/CDN) must pass the `X-Forwarded-Prefix` header to the SSR process without sanitization.\n- The cache must not vary on the `X-Forwarded-Prefix` header.\n\n### Patches\n- 21.2.0-rc.1\n- 21.1.5\n- 20.3.17\n- 19.2.21\n\n### Workarounds\nUntil the patch is applied, developers should sanitize the `X-Forwarded-Prefix` header in their`server.ts` before the Angular engine processes the request:\n\n```ts\napp.use((req, res, next) =\u003e {\n  const prefix = req.headers['x-forwarded-prefix']?.trim();\n  if (prefix) {\n    // Sanitize by removing all leading slashes\n    req.headers['x-forwarded-prefix'] = prefix.replace(/^[/\\\\]+/, '/');\n  }\n  next();\n});\n\n```\n\n### Resources\n- [Report](https://github.com/angular/angular-cli/issues/32501)\n- [Fix](https://github.com/angular/angular-cli/pull/32521)","aliases":["CVE-2026-27738"],"modified":"2026-04-02T13:44:28.198028039Z","published":"2026-02-25T22:41:57Z","related":["CVE-2026-33397"],"database_specific":{"cwe_ids":["CWE-601"],"severity":"MODERATE","github_reviewed":true,"github_reviewed_at":"2026-02-25T22:41:57Z","nvd_published_at":"2026-02-25T17:25:40Z"},"references":[{"type":"WEB","url":"https://github.com/angular/angular-cli/security/advisories/GHSA-xh43-g2fq-wjrj"},{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-27738"},{"type":"WEB","url":"https://github.com/angular/angular-cli/issues/32501"},{"type":"WEB","url":"https://github.com/angular/angular-cli/pull/32521"},{"type":"WEB","url":"https://github.com/angular/angular-cli/commit/f086eccc36d10cf01c426e35864bc32e1e292323"},{"type":"PACKAGE","url":"https://github.com/angular/angular-cli"}],"affected":[{"package":{"name":"@angular/ssr","ecosystem":"npm","purl":"pkg:npm/%40angular/ssr"},"ranges":[{"type":"SEMVER","events":[{"introduced":"21.2.0-next.0"},{"fixed":"21.2.0-rc.1"}]}],"database_specific":{"last_known_affected_version_range":"\u003c 21.2.0-rc.0","source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/02/GHSA-xh43-g2fq-wjrj/GHSA-xh43-g2fq-wjrj.json"}},{"package":{"name":"@angular/ssr","ecosystem":"npm","purl":"pkg:npm/%40angular/ssr"},"ranges":[{"type":"SEMVER","events":[{"introduced":"21.0.0-next.0"},{"fixed":"21.1.5"}]}],"database_specific":{"source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/02/GHSA-xh43-g2fq-wjrj/GHSA-xh43-g2fq-wjrj.json"}},{"package":{"name":"@angular/ssr","ecosystem":"npm","purl":"pkg:npm/%40angular/ssr"},"ranges":[{"type":"SEMVER","events":[{"introduced":"20.0.0-next.0"},{"fixed":"20.3.17"}]}],"database_specific":{"source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/02/GHSA-xh43-g2fq-wjrj/GHSA-xh43-g2fq-wjrj.json"}},{"package":{"name":"@angular/ssr","ecosystem":"npm","purl":"pkg:npm/%40angular/ssr"},"ranges":[{"type":"SEMVER","events":[{"introduced":"19.0.0-next.0"},{"fixed":"19.2.21"}]}],"database_specific":{"source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/02/GHSA-xh43-g2fq-wjrj/GHSA-xh43-g2fq-wjrj.json"}}],"schema_version":"1.9.0","severity":[{"type":"CVSS_V4","score":"CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:N/SC:L/SI:L/SA:N"}]}