{"id":"CVE-2026-111754","aliases":["CLSA-2026-1793093788","CLSA-2026-1793911122","CLSA-2026-1793911707","CLSA-2026-1793917233","CLSA-2026-1793918325","CLSA-2026-1793919513","CLSA-2026-1793920447","CLSA-2026-1793920842","CLSA-2026-1793922812","CLSA-2026-1793930090","CLSA-2026-1793932915","EUVD-2026-116377","GHSA-w739-gvwx-grc3"],"status":"published","title":"Angular: Open Redirect via Protocol-Relative URLs in Server-Side Rendering (SSR)","description":"Angular is a development platform for building mobile and desktop web applications using TypeScript/JavaScript and other languages. Prior to 20.3.33, 21.2.25, and 22.2.1, ServerPlatformLocation in Angular server-side rendering checks for protocol-relative URLs before WHATWG URL normalization. A request path containing a popping dot segment followed by multiple slashes can bypass the raw resolveUrl check and normalize to a pathname beginning with two slashes. When Angular SSR detects a mismatch with the router's final location, it can place that pathname in an HTTP Location header, causing a browser to navigate to an attacker-controlled origin. Affected applications use @angular/platform-server and @angular/ssr and either expose compatible parameter or child route shapes or pass user-controlled navigation targets through infrastructure that preserves the relevant dot segments or semicolons. Pure client-side SPAs are not affected. This issue is fixed in versions 20.3.33, 21.2.25, and 22.2.1.","severity":{"version":"4.0","score":5.1,"vector":"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","level":"medium","assessor":"cna","from":"cve"},"epss":{"day":"2026-11-12","score":0.00977,"percentile":0.62639,"model":"v2026.06.15"},"facts":{"in_kev":false,"known_exploited":false,"public_exploit":false,"fix_available":true},"cwes":["CWE-601"],"published":"2026-10-20T14:35:49Z","modified":"2026-11-06T13:15:18Z","fixes":[{"ecosystem":"npm","package":"@angular/platform-server","fixed_in":["22.2.1","21.2.25","20.3.33"],"sources":["ghsa","osv"]}],"affected":[{"source":"ghsa","ecosystem":"npm","package":"@angular/platform-server","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"22.0.0"},{"fixed":"22.2.1"}]}]},{"source":"ghsa","ecosystem":"npm","package":"@angular/platform-server","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"21.0.0"},{"fixed":"21.2.25"}]}]},{"source":"ghsa","ecosystem":"npm","package":"@angular/platform-server","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"20.0.0"},{"fixed":"20.3.33"}]}]},{"source":"ghsa","ecosystem":"npm","package":"@angular/platform-server","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"last_affected":"19.2.25"}]}]},{"source":"osv","ecosystem":"TuxCare:npm","package":"@angular/bazel","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"19.2.25-tuxcare.0"},{"fixed":"19.2.25-tuxcare.7"}]}],"versions":["19.2.25","19.2.25-tuxcare.1","19.2.25-tuxcare.2","19.2.25-tuxcare.3","19.2.25-tuxcare.4","19.2.25-tuxcare.5","19.2.25-tuxcare.6"],"bundled":3},{"source":"osv","ecosystem":"TuxCare:npm","package":"@angular/language-service","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"19.2.25-tuxcare.0"},{"fixed":"19.2.25-tuxcare.7"}]}],"versions":["19.2.25","19.2.25-tuxcare.1","19.2.25-tuxcare.2","19.2.25-tuxcare.3","19.2.25-tuxcare.4","19.2.25-tuxcare.5","19.2.25-tuxcare.6"],"bundled":3},{"source":"osv","ecosystem":"TuxCare:npm","package":"@angular/language-service","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"19.2.14-tuxcare.0"},{"fixed":"19.2.14-tuxcare.8"}]}],"versions":["19.2.14","19.2.14-tuxcare.1","19.2.14-tuxcare.2","19.2.14-tuxcare.3","19.2.14-tuxcare.4","19.2.14-tuxcare.5","19.2.14-tuxcare.6","19.2.14-tuxcare.7"],"bundled":4},{"source":"osv","ecosystem":"TuxCare:npm","package":"@angular/language-service","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"19.2.18-tuxcare.0"},{"fixed":"19.2.18-tuxcare.8"}]}],"versions":["19.2.18","19.2.18-tuxcare.1","19.2.18-tuxcare.2","19.2.18-tuxcare.3","19.2.18-tuxcare.4","19.2.18-tuxcare.5","19.2.18-tuxcare.6","19.2.18-tuxcare.7"],"bundled":4},{"source":"osv","ecosystem":"TuxCare:npm","package":"@angular/language-service","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"18.2.13-tuxcare.0"},{"fixed":"18.2.13-tuxcare.7"}]}],"versions":["18.2.13","18.2.13-tuxcare.1","18.2.13-tuxcare.2","18.2.13-tuxcare.3","18.2.13-tuxcare.4","18.2.13-tuxcare.5","18.2.13-tuxcare.6"],"bundled":4},{"source":"osv","ecosystem":"TuxCare:npm","package":"@angular/bazel","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"18.2.12-tuxcare.0"},{"fixed":"18.2.12-tuxcare.11"}]}],"versions":["18.2.12","18.2.12-tuxcare.1","18.2.12-tuxcare.10","18.2.12-tuxcare.2","18.2.12-tuxcare.3","18.2.12-tuxcare.4","18.2.12-tuxcare.5","18.2.12-tuxcare.6","18.2.12-tuxcare.7","18.2.12-tuxcare.8","18.2.12-tuxcare.9"],"bundled":4},{"source":"osv","ecosystem":"TuxCare:npm","package":"@angular/benchpress","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"18.2.12-tuxcare.0"},{"fixed":"18.2.12-tuxcare.11"}]}],"versions":["18.2.12","18.2.12-tuxcare.1","18.2.12-tuxcare.10","18.2.12-tuxcare.2","18.2.12-tuxcare.3","18.2.12-tuxcare.4","18.2.12-tuxcare.5","18.2.12-tuxcare.6","18.2.12-tuxcare.7","18.2.12-tuxcare.8","18.2.12-tuxcare.9"],"bundled":4},{"source":"osv","ecosystem":"TuxCare:npm","package":"@angular/language-service","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"18.2.12-tuxcare.0"},{"fixed":"18.2.12-tuxcare.11"}]}],"versions":["18.2.12","18.2.12-tuxcare.1","18.2.12-tuxcare.10","18.2.12-tuxcare.2","18.2.12-tuxcare.3","18.2.12-tuxcare.4","18.2.12-tuxcare.5","18.2.12-tuxcare.6","18.2.12-tuxcare.7","18.2.12-tuxcare.8","18.2.12-tuxcare.9"],"bundled":4},{"source":"osv","ecosystem":"TuxCare:npm","package":"@angular/bazel","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"18.1.2-tuxcare.0"},{"fixed":"18.1.2-tuxcare.11"}]}],"versions":["18.1.2","18.1.2-tuxcare.1","18.1.2-tuxcare.10","18.1.2-tuxcare.2","18.1.2-tuxcare.3","18.1.2-tuxcare.4","18.1.2-tuxcare.5","18.1.2-tuxcare.6","18.1.2-tuxcare.7","18.1.2-tuxcare.8","18.1.2-tuxcare.9"],"bundled":4},{"source":"osv","ecosystem":"TuxCare:npm","package":"@angular/benchpress","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"18.1.2-tuxcare.0"},{"fixed":"18.1.2-tuxcare.11"}]}],"versions":["18.1.2","18.1.2-tuxcare.1","18.1.2-tuxcare.10","18.1.2-tuxcare.2","18.1.2-tuxcare.3","18.1.2-tuxcare.4","18.1.2-tuxcare.5","18.1.2-tuxcare.6","18.1.2-tuxcare.7","18.1.2-tuxcare.8","18.1.2-tuxcare.9"],"bundled":4},{"source":"osv","ecosystem":"TuxCare:npm","package":"@angular/language-service","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"18.1.2-tuxcare.0"},{"fixed":"18.1.2-tuxcare.11"}]}],"versions":["18.1.2","18.1.2-tuxcare.1","18.1.2-tuxcare.10","18.1.2-tuxcare.2","18.1.2-tuxcare.3","18.1.2-tuxcare.4","18.1.2-tuxcare.5","18.1.2-tuxcare.6","18.1.2-tuxcare.7","18.1.2-tuxcare.8","18.1.2-tuxcare.9"],"bundled":4},{"source":"osv","ecosystem":"TuxCare:npm","package":"@angular/bazel","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"17.3.12-tuxcare.0"},{"fixed":"17.3.12-tuxcare.21"}]}],"versions":["17.3.12","17.3.12-tuxcare.1","17.3.12-tuxcare.10","17.3.12-tuxcare.11","17.3.12-tuxcare.12","17.3.12-tuxcare.13","17.3.12-tuxcare.14","17.3.12-tuxcare.15","17.3.12-tuxcare.16","17.3.12-tuxcare.17","17.3.12-tuxcare.18","17.3.12-tuxcare.2","17.3.12-tuxcare.3","17.3.12-tuxcare.4","17.3.12-tuxcare.5","17.3.12-tuxcare.6","17.3.12-tuxcare.7","17.3.12-tuxcare.8","17.3.12-tuxcare.9"],"bundled":4},{"source":"osv","ecosystem":"TuxCare:npm","package":"@angular/benchpress","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"17.3.12-tuxcare.0"},{"fixed":"17.3.12-tuxcare.21"}]}],"versions":["17.3.12","17.3.12-tuxcare.1","17.3.12-tuxcare.10","17.3.12-tuxcare.11","17.3.12-tuxcare.12","17.3.12-tuxcare.13","17.3.12-tuxcare.14","17.3.12-tuxcare.15","17.3.12-tuxcare.16","17.3.12-tuxcare.17","17.3.12-tuxcare.18","17.3.12-tuxcare.2","17.3.12-tuxcare.3","17.3.12-tuxcare.4","17.3.12-tuxcare.5","17.3.12-tuxcare.6","17.3.12-tuxcare.7","17.3.12-tuxcare.8","17.3.12-tuxcare.9"],"bundled":4},{"source":"osv","ecosystem":"TuxCare:npm","package":"@angular/language-service","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"17.3.12-tuxcare.0"},{"fixed":"17.3.12-tuxcare.21"}]}],"versions":["17.3.12","17.3.12-tuxcare.1","17.3.12-tuxcare.10","17.3.12-tuxcare.11","17.3.12-tuxcare.12","17.3.12-tuxcare.13","17.3.12-tuxcare.14","17.3.12-tuxcare.15","17.3.12-tuxcare.16","17.3.12-tuxcare.17","17.3.12-tuxcare.18","17.3.12-tuxcare.2","17.3.12-tuxcare.3","17.3.12-tuxcare.4","17.3.12-tuxcare.5","17.3.12-tuxcare.6","17.3.12-tuxcare.7","17.3.12-tuxcare.8","17.3.12-tuxcare.9"],"bundled":4},{"source":"osv","ecosystem":"TuxCare:npm","package":"@angular/bazel","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"18.2.14-tuxcare.0"},{"fixed":"18.2.14-tuxcare.18"}]}],"versions":["18.2.14","18.2.14-tuxcare.1","18.2.14-tuxcare.10","18.2.14-tuxcare.11","18.2.14-tuxcare.12","18.2.14-tuxcare.13","18.2.14-tuxcare.14","18.2.14-tuxcare.15","18.2.14-tuxcare.16","18.2.14-tuxcare.17","18.2.14-tuxcare.2","18.2.14-tuxcare.3","18.2.14-tuxcare.4","18.2.14-tuxcare.5","18.2.14-tuxcare.6","18.2.14-tuxcare.7","18.2.14-tuxcare.8","18.2.14-tuxcare.9"],"bundled":4},{"source":"osv","ecosystem":"TuxCare:npm","package":"@angular/benchpress","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"18.2.14-tuxcare.0"},{"fixed":"18.2.14-tuxcare.18"}]}],"versions":["18.2.14","18.2.14-tuxcare.1","18.2.14-tuxcare.10","18.2.14-tuxcare.11","18.2.14-tuxcare.12","18.2.14-tuxcare.13","18.2.14-tuxcare.14","18.2.14-tuxcare.15","18.2.14-tuxcare.16","18.2.14-tuxcare.17","18.2.14-tuxcare.2","18.2.14-tuxcare.3","18.2.14-tuxcare.4","18.2.14-tuxcare.5","18.2.14-tuxcare.6","18.2.14-tuxcare.7","18.2.14-tuxcare.8","18.2.14-tuxcare.9"],"bundled":4},{"source":"osv","ecosystem":"TuxCare:npm","package":"@angular/language-service","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"18.2.14-tuxcare.0"},{"fixed":"18.2.14-tuxcare.18"}]}],"versions":["18.2.14","18.2.14-tuxcare.1","18.2.14-tuxcare.10","18.2.14-tuxcare.11","18.2.14-tuxcare.12","18.2.14-tuxcare.13","18.2.14-tuxcare.14","18.2.14-tuxcare.15","18.2.14-tuxcare.16","18.2.14-tuxcare.17","18.2.14-tuxcare.2","18.2.14-tuxcare.3","18.2.14-tuxcare.4","18.2.14-tuxcare.5","18.2.14-tuxcare.6","18.2.14-tuxcare.7","18.2.14-tuxcare.8","18.2.14-tuxcare.9"],"bundled":4},{"source":"osv","ecosystem":"TuxCare:npm","package":"@angular/bazel","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"17.1.0-tuxcare.0"},{"fixed":"17.1.0-tuxcare.10"}]}],"versions":["17.1.0","17.1.0-tuxcare.1","17.1.0-tuxcare.2","17.1.0-tuxcare.3","17.1.0-tuxcare.4","17.1.0-tuxcare.5","17.1.0-tuxcare.6","17.1.0-tuxcare.7","17.1.0-tuxcare.8","17.1.0-tuxcare.9"],"bundled":4},{"source":"osv","ecosystem":"TuxCare:npm","package":"@angular/benchpress","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"17.1.0-tuxcare.0"},{"fixed":"17.1.0-tuxcare.10"}]}],"versions":["17.1.0","17.1.0-tuxcare.1","17.1.0-tuxcare.2","17.1.0-tuxcare.3","17.1.0-tuxcare.4","17.1.0-tuxcare.5","17.1.0-tuxcare.6","17.1.0-tuxcare.7","17.1.0-tuxcare.8","17.1.0-tuxcare.9"],"bundled":4},{"source":"osv","ecosystem":"TuxCare:npm","package":"@angular/language-service","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"17.1.0-tuxcare.0"},{"fixed":"17.1.0-tuxcare.10"}]}],"versions":["17.1.0","17.1.0-tuxcare.1","17.1.0-tuxcare.2","17.1.0-tuxcare.3","17.1.0-tuxcare.4","17.1.0-tuxcare.5","17.1.0-tuxcare.6","17.1.0-tuxcare.7","17.1.0-tuxcare.8","17.1.0-tuxcare.9"],"bundled":4},{"source":"osv","ecosystem":"TuxCare:npm","package":"@angular/bazel","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"19.2.23-tuxcare.0"},{"fixed":"19.2.23-tuxcare.8"}]}],"versions":["19.2.23","19.2.23-tuxcare.1","19.2.23-tuxcare.2","19.2.23-tuxcare.3","19.2.23-tuxcare.4","19.2.23-tuxcare.5","19.2.23-tuxcare.6","19.2.23-tuxcare.7"],"bundled":4},{"source":"osv","ecosystem":"TuxCare:npm","package":"@angular/benchpress","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"19.2.23-tuxcare.0"},{"fixed":"19.2.23-tuxcare.8"}]}],"versions":["19.2.23","19.2.23-tuxcare.1","19.2.23-tuxcare.2","19.2.23-tuxcare.3","19.2.23-tuxcare.4","19.2.23-tuxcare.5","19.2.23-tuxcare.6","19.2.23-tuxcare.7"],"bundled":4},{"source":"osv","ecosystem":"TuxCare:npm","package":"@angular/language-service","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"19.2.23-tuxcare.0"},{"fixed":"19.2.23-tuxcare.8"}]}],"versions":["19.2.23","19.2.23-tuxcare.1","19.2.23-tuxcare.2","19.2.23-tuxcare.3","19.2.23-tuxcare.4","19.2.23-tuxcare.5","19.2.23-tuxcare.6","19.2.23-tuxcare.7"],"bundled":4},{"source":"osv","ecosystem":"TuxCare:npm","package":"@angular/bazel","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"19.2.21-tuxcare.0"},{"fixed":"19.2.21-tuxcare.10"}]}],"versions":["19.2.21","19.2.21-tuxcare.2","19.2.21-tuxcare.4","19.2.21-tuxcare.5","19.2.21-tuxcare.6","19.2.21-tuxcare.7","19.2.21-tuxcare.8","19.2.21-tuxcare.9"],"bundled":4},{"source":"osv","ecosystem":"TuxCare:npm","package":"@angular/benchpress","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"19.2.21-tuxcare.0"},{"fixed":"19.2.21-tuxcare.10"}]}],"versions":["19.2.21","19.2.21-tuxcare.2","19.2.21-tuxcare.4","19.2.21-tuxcare.5","19.2.21-tuxcare.6","19.2.21-tuxcare.7","19.2.21-tuxcare.8","19.2.21-tuxcare.9"],"bundled":4},{"source":"osv","ecosystem":"TuxCare:npm","package":"@angular/language-service","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"19.2.21-tuxcare.0"},{"fixed":"19.2.21-tuxcare.10"}]}],"versions":["19.2.21","19.2.21-tuxcare.2","19.2.21-tuxcare.4","19.2.21-tuxcare.5","19.2.21-tuxcare.6","19.2.21-tuxcare.7","19.2.21-tuxcare.8","19.2.21-tuxcare.9"],"bundled":4},{"source":"osv","ecosystem":"npm","package":"@angular/platform-server","ranges":[{"type":"SEMVER","events":[{"introduced":"22.0.0"},{"fixed":"22.2.1"}]}]},{"source":"osv","ecosystem":"npm","package":"@angular/platform-server","ranges":[{"type":"SEMVER","events":[{"introduced":"21.0.0"},{"fixed":"21.2.25"}]}]},{"source":"osv","ecosystem":"npm","package":"@angular/platform-server","ranges":[{"type":"SEMVER","events":[{"introduced":"20.0.0"},{"fixed":"20.3.33"}]}]},{"source":"osv","ecosystem":"npm","package":"@angular/platform-server","ranges":[{"type":"SEMVER","events":[{"introduced":"0"},{"last_affected":"19.2.25"}]}]}],"products":[{"vendor":"angular","product":"angular"}],"references":[{"url":"https://github.com/angular/angular/security/advisories/GHSA-w739-gvwx-grc3","tags":["x_refsource_CONFIRM","advisory","web"]},{"url":"https://github.com/angular/angular/issues/71076","tags":["x_refsource_MISC","report"]},{"url":"https://github.com/angular/angular/pull/71077","tags":["x_refsource_MISC","fix","web"]},{"url":"https://github.com/angular/angular/pull/71078","tags":["x_refsource_MISC","fix","web"]},{"url":"https://github.com/angular/angular/pull/71079","tags":["x_refsource_MISC","fix","web"]},{"url":"https://github.com/angular/angular/commit/450af9c813c7660b9bd91e5635f705ee3ed7b32a","tags":["x_refsource_MISC","fix","web"]},{"url":"https://github.com/angular/angular/commit/83944fc8c50e86be90e8ec4184cd15002b5af262","tags":["x_refsource_MISC","fix","web"]},{"url":"https://github.com/angular/angular/commit/928dcfd2582152655b5559509d057bf6a5a19521","tags":["x_refsource_MISC","fix","web"]},{"url":"https://github.com/angular/angular/releases/tag/v20.3.33","tags":["x_refsource_MISC","web"]},{"url":"https://github.com/angular/angular/releases/tag/v21.2.25","tags":["x_refsource_MISC","web"]},{"url":"https://github.com/angular/angular/releases/tag/v22.2.1","tags":["x_refsource_MISC","web"]},{"url":"https://github.com/angular/angular/commit/d7d81e189d227108c3b9d39178dbb7389f6f970d","tags":["web"]},{"url":"https://github.com/advisories/GHSA-w739-gvwx-grc3"},{"url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/111xxx/CVE-2026-111754.json","tags":["advisory"]},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-111754","tags":["advisory"]},{"url":"https://github.com/angular/angular","tags":["package"]}],"sources":{"cve":[{"id":"CVE-2026-111754","title":"Angular: Open Redirect via Protocol-Relative URLs in Server-Side Rendering (SSR)","description":"Angular is a development platform for building mobile and desktop web applications using TypeScript/JavaScript and other languages. Prior to 20.3.33, 21.2.25, and 22.2.1, ServerPlatformLocation in Angular server-side rendering checks for protocol-relative URLs before WHATWG URL normalization. A request path containing a popping dot segment followed by multiple slashes can bypass the raw resolveUrl check and normalize to a pathname beginning with two slashes. When Angular SSR detects a mismatch with the router's final location, it can place that pathname in an HTTP Location header, causing a browser to navigate to an attacker-controlled origin. Affected applications use @angular/platform-server and @angular/ssr and either expose compatible parameter or child route shapes or pass user-controlled navigation targets through infrastructure that preserves the relevant dot segments or semicolons. Pure client-side SPAs are not affected. This issue is fixed in versions 20.3.33, 21.2.25, and 22.2.1.","status":"published","published":"2026-11-03T20:55:11.497Z","modified":"2026-11-03T21:23:55.644Z","cvss":[{"version":"4.0","score":5.1,"vector":"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","level":"medium","assessor":"cna"}],"cwes":["CWE-601"],"updated_at":"2026-11-03T22:58:36.650985Z"}],"euvd":[{"id":"EUVD-2026-116377","description":"Angular is a development platform for building mobile and desktop web applications using TypeScript/JavaScript and other languages. Prior to 20.3.33, 21.2.25, and 22.2.1, ServerPlatformLocation in Angular server-side rendering checks for protocol-relative URLs before WHATWG URL normalization. A request path containing a popping dot segment followed by multiple slashes can bypass the raw resolveUrl check and normalize to a pathname beginning with two slashes. When Angular SSR detects a mismatch with the router's final location, it can place that pathname in an HTTP Location header, causing a browser to navigate to an attacker-controlled origin. Affected applications use @angular/platform-server and @angular/ssr and either expose compatible parameter or child route shapes or pass user-controlled navigation targets through infrastructure that preserves the relevant dot segments or semicolons. Pure client-side SPAs are not affected. This issue is fixed in versions 20.3.33, 21.2.25, and 22.2.1.","status":"published","published":"2026-11-03T20:55:11Z","modified":"2026-11-03T21:23:55Z","cvss":[{"version":"4.0","score":5.1,"vector":"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","level":"medium"}],"updated_at":"2026-11-03T23:01:36.527063Z"}],"ghsa":[{"id":"GHSA-w739-gvwx-grc3","title":"@angular/platform-server: Open Redirect via Protocol-Relative URLs in Server-Side Rendering (SSR)","description":"An open redirect vulnerability was identified in `@angular/platform-server` when Server-Side Rendering (SSR) is enabled.\n\nWhen 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.\n\nWhen 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`).\n\nConsequently, `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.\n\n### Impact\n\nSuccessful exploitation allows an unauthenticated remote attacker to craft URLs that trick Angular SSR into redirecting users to an arbitrary external domain.\n\n* **Bypasses Application-Level Guards:** Common application-level validation routines (such as checking `!returnUrl.startsWith('//')` before invoking `router.navigateByUrl`) accept `/.//evil.test` or `/.;/(//evil.test)` as a safe relative path, allowing attackers to bypass redirect allowlists.\n* **Client-side SPAs Unaffected:** Pure client-side Angular applications (Single Page Applications without SSR) are **not** vulnerable, as `ServerPlatformLocation` is only utilized in server-side execution environments.\n\n### Attack Preconditions \u0026 Vulnerable Configurations\n\nAn application is affected if the following conditions are met:\n\n* **SSR Enabled:** The application runs in a Server-Side Rendering environment using `@angular/platform-server` and `@angular/ssr`.\n* **Parameter Route Shapes:** The router contains parameter routes with wildcard or child segments (e.g. `/:tenant` matching `.` and serializing secondary outlet groups `(//evil.test)` to `/.//evil.test`), or passes user-provided navigation targets (e.g. `returnUrl`).\n* **Reverse Proxy Passthrough:** Upstream reverse proxies (Nginx, Cloudflare, ALB) pass semicolons (`;`) or dot-segments without stripping or normalizing them.\n\n#### Exploit Payload Example\n\nAn attacker sends a request targeting a route with parameters and child segments:\n\n```http\nGET /.;/(//evil.test) HTTP/1.1\nHost: example.com\n```\n\n**Response:**\n```http\nHTTP/1.1 302 Found\nLocation: //evil.test\n```\n\nThe client browser resolves `//evil.test` protocol-relatively and redirects the user away from `example.com` to `evil.test`.\n\n### Patches\n\nThe issue is resolved by updating `resolveUrl` (and `parseUrl` in v20) in `@angular/platform-server` to verify that the normalized URL pathname does not start with `//` when `allowProtocolRelative` is `false`.\n\n* `22.2.1`\n* `21.2.25`\n* `20.3.33`\n\n### Workarounds \u0026 Mitigations\n\nIf you cannot immediately upgrade to a patched version, apply one of the following mitigations at your edge reverse proxy or WAF:\n\n1. **Reject Paths with Dot-Segments Followed by Slashes:**\n   Configure your reverse proxy (e.g., Nginx, Cloudflare, AWS WAF) to block requests containing `/.//`, `/..//`, or `/.;/`:\n   ```nginx\n   # Nginx example: reject suspicious path normalization sequences\n   if ($request_uri ~* \"(\\n/\\.\\/|\\/\\.\\;)\") {\n       return 400;\n   }\n   ```\n2. **Sanitize Redirect Headers:**\n   Ensure edge proxies or API gateways rewrite or disallow protocol-relative (`//`) `Location` response headers originating from the SSR upstream.","status":"published","published":"2026-10-20T14:35:49Z","modified":"2026-10-20T14:35:51Z","cvss":[{"version":"4.0","score":5.1,"vector":"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","level":"medium"}],"cwes":["CWE-601"],"updated_at":"2026-11-02T14:41:33.669646Z"}],"nvd":[{"id":"CVE-2026-111754","description":"Angular is a development platform for building mobile and desktop web applications using TypeScript/JavaScript and other languages. Prior to 20.3.33, 21.2.25, and 22.2.1, ServerPlatformLocation in Angular server-side rendering checks for protocol-relative URLs before WHATWG URL normalization. A request path containing a popping dot segment followed by multiple slashes can bypass the raw resolveUrl check and normalize to a pathname beginning with two slashes. When Angular SSR detects a mismatch with the router's final location, it can place that pathname in an HTTP Location header, causing a browser to navigate to an attacker-controlled origin. Affected applications use @angular/platform-server and @angular/ssr and either expose compatible parameter or child route shapes or pass user-controlled navigation targets through infrastructure that preserves the relevant dot segments or semicolons. Pure client-side SPAs are not affected. This issue is fixed in versions 20.3.33, 21.2.25, and 22.2.1.","status":"published","published":"2026-11-03T21:16:58.203Z","modified":"2026-11-12T20:04:52.377Z","cvss":[{"version":"4.0","score":5.1,"vector":"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/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X","level":"medium","assessor":"secondary"}],"cwes":["CWE-601"],"updated_at":"2026-11-12T21:32:41.877972Z"}],"osv":[{"id":"CVE-2026-111754","title":"Angular: Open Redirect via Protocol-Relative URLs in Server-Side Rendering (SSR)","description":"Angular is a development platform for building mobile and desktop web applications using TypeScript/JavaScript and other languages. Prior to 20.3.33, 21.2.25, and 22.2.1, ServerPlatformLocation in Angular server-side rendering checks for protocol-relative URLs before WHATWG URL normalization. A request path containing a popping dot segment followed by multiple slashes can bypass the raw resolveUrl check and normalize to a pathname beginning with two slashes. When Angular SSR detects a mismatch with the router's final location, it can place that pathname in an HTTP Location header, causing a browser to navigate to an attacker-controlled origin. Affected applications use @angular/platform-server and @angular/ssr and either expose compatible parameter or child route shapes or pass user-controlled navigation targets through infrastructure that preserves the relevant dot segments or semicolons. Pure client-side SPAs are not affected. This issue is fixed in versions 20.3.33, 21.2.25, and 22.2.1.","status":"published","published":"2026-11-03T20:55:11.497Z","modified":"2026-11-11T10:47:24.790420935Z","cvss":[{"version":"4.0","score":5.1,"vector":"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","level":"medium"}],"cwes":["CWE-601"],"updated_at":"2026-11-11T02:50:43.46164Z"},{"id":"GHSA-w739-gvwx-grc3","title":"@angular/platform-server: Open Redirect via Protocol-Relative URLs in Server-Side Rendering (SSR)","description":"An open redirect vulnerability was identified in `@angular/platform-server` when Server-Side Rendering (SSR) is enabled.\n\nWhen 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.\n\nWhen 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`).\n\nConsequently, `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.\n\n### Impact\n\nSuccessful exploitation allows an unauthenticated remote attacker to craft URLs that trick Angular SSR into redirecting users to an arbitrary external domain.\n\n* **Bypasses Application-Level Guards:** Common application-level validation routines (such as checking `!returnUrl.startsWith('//')` before invoking `router.navigateByUrl`) accept `/.//evil.test` or `/.;/(//evil.test)` as a safe relative path, allowing attackers to bypass redirect allowlists.\n* **Client-side SPAs Unaffected:** Pure client-side Angular applications (Single Page Applications without SSR) are **not** vulnerable, as `ServerPlatformLocation` is only utilized in server-side execution environments.\n\n### Attack Preconditions \u0026 Vulnerable Configurations\n\nAn application is affected if the following conditions are met:\n\n* **SSR Enabled:** The application runs in a Server-Side Rendering environment using `@angular/platform-server` and `@angular/ssr`.\n* **Parameter Route Shapes:** The router contains parameter routes with wildcard or child segments (e.g. `/:tenant` matching `.` and serializing secondary outlet groups `(//evil.test)` to `/.//evil.test`), or passes user-provided navigation targets (e.g. `returnUrl`).\n* **Reverse Proxy Passthrough:** Upstream reverse proxies (Nginx, Cloudflare, ALB) pass semicolons (`;`) or dot-segments without stripping or normalizing them.\n\n#### Exploit Payload Example\n\nAn attacker sends a request targeting a route with parameters and child segments:\n\n```http\nGET /.;/(//evil.test) HTTP/1.1\nHost: example.com\n```\n\n**Response:**\n```http\nHTTP/1.1 302 Found\nLocation: //evil.test\n```\n\nThe client browser resolves `//evil.test` protocol-relatively and redirects the user away from `example.com` to `evil.test`.\n\n### Patches\n\nThe issue is resolved by updating `resolveUrl` (and `parseUrl` in v20) in `@angular/platform-server` to verify that the normalized URL pathname does not start with `//` when `allowProtocolRelative` is `false`.\n\n* `22.2.1`\n* `21.2.25`\n* `20.3.33`\n\n### Workarounds \u0026 Mitigations\n\nIf you cannot immediately upgrade to a patched version, apply one of the following mitigations at your edge reverse proxy or WAF:\n\n1. **Reject Paths with Dot-Segments Followed by Slashes:**\n   Configure your reverse proxy (e.g., Nginx, Cloudflare, AWS WAF) to block requests containing `/.//`, `/..//`, or `/.;/`:\n   ```nginx\n   # Nginx example: reject suspicious path normalization sequences\n   if ($request_uri ~* \"(\\n/\\.\\/|\\/\\.\\;)\") {\n       return 400;\n   }\n   ```\n2. **Sanitize Redirect Headers:**\n   Ensure edge proxies or API gateways rewrite or disallow protocol-relative (`//`) `Location` response headers originating from the SSR upstream.","status":"published","published":"2026-10-20T14:35:49Z","modified":"2026-10-20T14:45:03.771349618Z","cvss":[{"version":"4.0","score":5.1,"vector":"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","level":"medium"}],"cwes":["CWE-601"],"updated_at":"2026-11-02T15:46:58.401149Z"},{"id":"CLSA-2026-1793093788","title":"TuxCare security update for @angular (3 CVEs)","description":"TuxCare rebuilt 2 @angular packages to address 3 CVEs. Fixed in 19.2.25-tuxcare.7.","status":"published","published":"2026-10-27T09:36:28Z","modified":"2026-10-27T13:30:04.773286986Z","updated_at":"2026-11-02T15:43:55.34846Z"},{"id":"CLSA-2026-1793911122","title":"TuxCare security update for @angular/language-service (4 CVEs)","description":"TuxCare rebuilt @angular/language-service to address 4 CVEs. Fixed in 19.2.14-tuxcare.8.","status":"published","published":"2026-11-05T21:38:43Z","modified":"2026-11-06T13:15:15.6754549Z","updated_at":"2026-11-06T13:44:09.891978Z"},{"id":"CLSA-2026-1793911707","title":"TuxCare security update for @angular/language-service (4 CVEs)","description":"TuxCare rebuilt @angular/language-service to address 4 CVEs. Fixed in 19.2.18-tuxcare.8.","status":"published","published":"2026-11-05T21:48:27Z","modified":"2026-11-06T13:15:18.53964347Z","updated_at":"2026-11-06T13:44:09.891978Z"},{"id":"CLSA-2026-1793917233","title":"TuxCare security update for @angular/language-service (4 CVEs)","description":"TuxCare rebuilt @angular/language-service to address 4 CVEs. Fixed in 18.2.13-tuxcare.7.","status":"published","published":"2026-11-05T23:20:34Z","modified":"2026-11-06T13:15:15.077683301Z","updated_at":"2026-11-06T13:44:09.891978Z"},{"id":"CLSA-2026-1793918325","title":"TuxCare security update for @angular (4 CVEs)","description":"TuxCare rebuilt 3 @angular packages to address 4 CVEs. Fixed in 18.2.12-tuxcare.11.","status":"published","published":"2026-11-05T23:38:46Z","modified":"2026-11-06T13:15:16.803884452Z","updated_at":"2026-11-06T13:44:09.891978Z"},{"id":"CLSA-2026-1793919513","title":"TuxCare security update for @angular (4 CVEs)","description":"TuxCare rebuilt 3 @angular packages to address 4 CVEs. Fixed in 18.1.2-tuxcare.11.","status":"published","published":"2026-11-05T23:58:34Z","modified":"2026-11-06T13:15:16.802787464Z","updated_at":"2026-11-06T13:44:09.891978Z"},{"id":"CLSA-2026-1793920447","title":"TuxCare security update for @angular (4 CVEs)","description":"TuxCare rebuilt 3 @angular packages to address 4 CVEs. Fixed in 17.3.12-tuxcare.21.","status":"published","published":"2026-11-06T00:14:07Z","modified":"2026-11-06T13:15:17.594757696Z","updated_at":"2026-11-06T13:44:09.891978Z"},{"id":"CLSA-2026-1793920842","title":"TuxCare security update for @angular (4 CVEs)","description":"TuxCare rebuilt 3 @angular packages to address 4 CVEs. Fixed in 18.2.14-tuxcare.18.","status":"published","published":"2026-11-06T00:20:42Z","modified":"2026-11-06T13:15:18.546131343Z","updated_at":"2026-11-06T13:44:09.891978Z"},{"id":"CLSA-2026-1793922812","title":"TuxCare security update for @angular (4 CVEs)","description":"TuxCare rebuilt 3 @angular packages to address 4 CVEs. Fixed in 17.1.0-tuxcare.10.","status":"published","published":"2026-11-06T00:53:33Z","modified":"2026-11-06T13:15:14.685193602Z","updated_at":"2026-11-06T13:44:09.891978Z"},{"id":"CLSA-2026-1793930090","title":"TuxCare security update for @angular (4 CVEs)","description":"TuxCare rebuilt 3 @angular packages to address 4 CVEs. Fixed in 19.2.23-tuxcare.8.","status":"published","published":"2026-11-06T02:54:50Z","modified":"2026-11-06T13:15:11.67065648Z","updated_at":"2026-11-06T13:44:09.891978Z"},{"id":"CLSA-2026-1793932915","title":"TuxCare security update for @angular (4 CVEs)","description":"TuxCare rebuilt 3 @angular packages to address 4 CVEs. Fixed in 19.2.21-tuxcare.10.","status":"published","published":"2026-11-06T03:41:56Z","modified":"2026-11-06T13:15:11.672468631Z","updated_at":"2026-11-06T13:44:09.891978Z"}]}}
