An independent re-analysis by Goldberg Security Research of a publicly disclosed vulnerability: our breakdown of root cause, exploitation, and defence. Discovery credit belongs to the original researchers (see references).
Summary
When a request was made with withCredentials: true, axios attached the value of
the XSRF-TOKEN cookie as the X-XSRF-TOKEN header on
every request — including cross-origin ones. The result: an application's
anti-CSRF token gets handed to whatever third-party host it talks to.
Root cause
The decision to attach the token used an || where it needed an &&.
With withCredentials truthy, the same-origin check was short-circuited entirely:
// simplified vulnerable logic
if (config.withCredentials || isURLSameOrigin(fullPath)) {
const xsrfValue = cookies.read(config.xsrfCookieName);
if (xsrfValue) {
// attached even when fullPath is a DIFFERENT origin
headers[config.xsrfHeaderName] = xsrfValue;
}
}
Because the OR is satisfied by withCredentials alone, isURLSameOrigin()
never gates the token — so it ships to any host.
Impact
Any app that uses axios with credentials to call a third-party API leaks its CSRF token to that party. A malicious or compromised endpoint can capture the token and replay it to forge authenticated state-changing requests against the victim app.
Remediation
- Upgrade to axios ≥ 1.6.0 (or 0.28.0 on the legacy line). The fix only sends the token same-origin.
- As defence-in-depth, scope credentialed requests narrowly and avoid reusing one axios instance across trusted and untrusted hosts.
Takeaway
A textbook example of a boolean operator silently widening a trust boundary — the kind of one-character logic flaw that survives review because the happy path works perfectly.