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.

References