- A GitHub advisory says Angular's fix for CVE-2025-66035 was incomplete, so XSRF tokens could be sent to attacker-controlled domains through specially written URLs.
- The cause is a mismatch: Angular's check read the URL as text, while browsers normalize it first. Fixed behavior compares origins using the standard URL parser.
- Teams should confirm their Angular versions, including the 20.3.x LTS branch, and review code that passes dynamic URLs to POST, PUT, DELETE or PATCH requests.
A security fix can close a ticket and still fail if it reads an address differently from the software that acts on it. That is the lesson of a new advisory about Angular's web request library. The check and the browser looked at the same URL and saw two different places.
What the advisory says
The GitHub Advisory Database published GHSA-jfgx-762w-99vr on October 20. It describes an incomplete fix for CVE-2025-66035 in the HTTP client of @angular/common. The flaw lets cross-site request forgery (XSRF) tokens leak to attacker-controlled domains. The advisory credits developer alan-agius4 with the remediation.
An XSRF token is a secret value that helps a server tell whether a request came from the application's own pages. Angular attaches it in an X-XSRF-TOKEN header. It is meant to go only to the application's own site.
How the mismatch works
To stop the token going elsewhere, the earlier fix added a text pattern. The pattern spotted URLs that begin with http://, https:// or just //, and skipped the token for them. Anything else was treated as a relative address on the same site.
Browsers do not read URLs as raw text. They pass them through the WHATWG URL standard, which cleans the address before deciding where to send it. The advisory lists three clean-up steps. Backslashes are treated as forward slashes. Leading and trailing control characters and spaces are stripped. Tabs, newlines and carriage returns are removed anywhere in the string.
So a string such as /\evil.example/x does not match Angular's pattern. Angular sees a same-site address and attaches the token. The browser cleans the string and sends the request to evil.example. The advisory's other examples include \\evil.example/x and 'htt\tps://evil.example/x'.
The advisory says an attacker who captures the token can then mount CSRF attacks against the victim's session. That requires the attacker's server to allow the request and the custom header through CORS, the browser rule that controls cross-site requests.
What limits the exposure
The advisory sets out two conditions. XSRF protection must be on, which is the default in HttpClient. Second, an outsider has to steer the application into sending a write-type request to a destination the outsider runs. The advisory names POST, PUT, DELETE and PATCH as examples of such requests.
The second condition matters. It points to application code that builds request addresses from input a user or outsider can influence. The advisory text does not describe any exploitation.
On versions, the advisory says Angular 21.0.3 and later, and 22.x, already replaced the pattern with an origin comparison and were unaffected. The 20.3.x long-term support branch kept the pattern until 20.3.34.
The real lesson: ask the parser that acts
The lesson here is about who gets the final say on what a URL means. The first fix tried to predict how browsers would interpret a URL by matching its text. The durable fix stops predicting. It parses the address with the standard URL constructor and compares its origin with the application's own.
Matching strings against a format that has many legal spellings is a familiar trap. The advisory shows that a closed ticket and a safe system are not the same thing. A team that marked CVE-2025-66035 as done had good reason to believe it.
The advisory says nothing about how the original fix was tested. That point is our inference. Whatever testing was done, it evidently missed inputs such as backslashes, stray control characters and embedded tabs.
The long-term support branch adds a second lesson. Organizations choose those branches for stability. Here, that choice meant the older pattern stayed in place longer than on newer releases.
What WebPulse can and cannot say
In WebPulse's September 2026 scan of the Tranco top 10,000 domains, a platform was detected on 2,491 sites. Angular was detected on 155 of them, or 6.2% of those detected sites. That is a sample, not the whole web.
This figure says nothing about exposure to this flaw. Detection cannot show an application's Angular version or whether its code passes outside URLs to mutating requests.
Questions to put to your team
Which Angular version does each customer-facing and internal application run, and are any on 20.3.x below 20.3.34? Does any code pass dynamic or user-influenced URLs to POST, PUT, DELETE or PATCH requests?
If upgrading must wait, the advisory suggests two workarounds. Parse each outgoing URL with new URL(url, window.location.origin) and confirm the origin matches before sending. And avoid giving untrusted URLs to mutating HttpClient methods.
Ask a third question about process. When a vulnerability fix is closed, did testing include unusual spellings of the same input, or only the clean examples? A check is only as strong as its agreement with the parser that carries out the request.
Produced by the WebPulse Newsroom with AI assistance from the original reporting credited below, and checked against that source by our editorial review. How we use AI.
Original reporting: GitHub Advisory Database.




