CVE-2026-40175: axios acted as a prototype pollution gadget, enabling CRLF header injection
Contents
In late March, the axios npm account was hijacked and a supply-chain attack dropped a RAT.
Subsequent investigation uncovered UNC1069’s social-engineering playbook and a broader campaign targeting Fastify, Lodash, and other maintainers.
CVE-2026-40175 is an entirely separate issue.
Not a supply-chain story — a vulnerability that had been present in axios’s own code all along, now patched.
Overview of CVE-2026-40175
According to the GitHub Advisory and NVD, axios’s config-merge logic picks up values sitting on a polluted Object.prototype (injected by a separate vulnerable library) and uses them as HTTP headers verbatim.
On top of that, header values were not validated for CRLF (\r\n), opening the door to header injection, request splitting, and SSRF (Server-Side Request Forgery).
- CVSS: 10.0 / 9.9
- Fixed in: 1.15.0
axios itself never pollutes the prototype. The core of this bug is that it acts as a dangerous gadget in an already-polluted world.
What is prototype pollution?
Every JavaScript object inherits from Object.prototype.
Prototype pollution is an attack where an attacker injects arbitrary properties onto Object.prototype, and every object created thereafter inherits those tainted values.
// prototype pollution example
const malicious = JSON.parse('{"__proto__": {"polluted": true}}');
merge({}, malicious); // a naive merge function pollutes Object.prototype
// every subsequent object is affected
const obj = {};
console.log(obj.polluted); // true — a value that was never explicitly set
The typical root cause is a recursive merge that does not special-case __proto__ or constructor.prototype.
JSON parsers, query-string parsers, and deep-merge libraries have shipped this bug repeatedly over the years.
Major libraries with past prototype pollution CVEs
| Library | CVE / Year | Impact |
|---|---|---|
lodash (_.merge, _.defaultsDeep) | CVE-2018-16487, CVE-2019-10744 | Pollution via deep merge |
jQuery ($.extend) | CVE-2019-11358 | Pollution via deep copy |
| Hoek (hapi) | CVE-2018-3728 | Pollution via deep clone |
| minimist | CVE-2020-7598 | Pollution via CLI argument parsing |
| qs | CVE-2022-24999 | Pollution via query-string parsing |
All of these are on the “pollution source” side. axios in CVE-2026-40175 is on the “pollution consumer” side — a gadget that turns a polluted prototype into a real exploit.
Attack chain
This vulnerability is not an axios-only attack.
It is a chained scenario: another library causes prototype pollution, and axios picks up that pollution and converts it into an actual HTTP-level attack.
graph TD
A["External input<br/>JSON / query string / etc."] --> B["Vulnerable library<br/>deep merge / parser"]
B --> C["Object.prototype polluted<br/>header name + value injected"]
C --> D["axios config merge<br/>picks up tainted properties"]
D --> E["HTTP request sent<br/>tainted values become headers"]
E --> F["CRLF injection succeeds<br/>newline characters in header value"]
F --> G1["Request splitting<br/>HTTP Request Smuggling"]
F --> G2["SSRF<br/>internal API / metadata theft"]
F --> G3["Auth header overwrite<br/>session hijacking"]
The key transition is steps 2 → 3 → 4: axios never pollutes the prototype itself.
But when running in a polluted environment, its config merge treats tainted values as legitimate configuration and passes them straight into HTTP headers.
If those values contain CRLF sequences, the attacker can forge header boundaries and request separators at the HTTP protocol level.
How CRLF header injection works in practice
HTTP headers are delimited by \r\n (CRLF).
If an attacker can inject CRLF into a header value, they can append arbitrary headers or forge a request body.
Normal request:
GET /api/data HTTP/1.1
Host: example.com
X-Custom: normalvalue
After CRLF injection:
GET /api/data HTTP/1.1
Host: example.com
X-Custom: injected\r\nX-Forwarded-For: 127.0.0.1\r\n\r\nGET /admin HTTP/1.1\r\nHost: internal-api
In the second example, injecting CRLF into the X-Custom header value forges an X-Forwarded-For header and injects an entirely second HTTP request (HTTP Request Smuggling).
On a Node.js server, if that second request targets an internal API, it becomes SSRF.
Reproduction sketch with axios
// assume Object.prototype is already polluted
Object.prototype['X-Injected'] =
'value\r\nX-Forwarded-For: 169.254.169.254';
// axios sends a request
const response = await axios.get('https://api.example.com/data');
// → X-Injected header is automatically attached
// → CRLF also injects X-Forwarded-For
axios’s config merge (mergeConfig) layers defaults → instance config → per-request config in sequence.
During this process, properties from Object.prototype leaked into the headers object and were sent as real HTTP headers.
The 1.15.0 fix adds validation that rejects header values containing \r or \n.
What the CVSS 10.0 actually means
A CVSS score of 10.0 (or 9.9) does not mean “instant death in every environment.”
NVD scores against the worst-case scenario, which in this case includes Node-side SSRF chaining into AWS IMDSv2 metadata retrieval and cloud privilege escalation.
| Environment | Risk | Reason |
|---|---|---|
| Node.js server (makes internal API calls) | High | Worst-case chain: SSRF → cloud metadata → privilege escalation |
| Serverless / Lambda | High | SSRF to the metadata endpoint is critical when running with an IAM role |
| CI / build pipelines | Medium–High | Secrets and tokens in env vars can be exfiltrated via SSRF |
| Browser frontend | Low | Same-origin policy applies; prototype pollution itself is unlikely in the browser |
The single biggest factor determining severity is whether the Node process can reach internal networks or cloud metadata endpoints.
Checklist: does this affect you?
If two or more of the following apply, prioritize the update:
- Running axios < 1.15.0
- Using axios on the server side (Node.js)
- Building axios requests from external input (URL, headers, or params)
- Dependency tree includes deep-merge or query-parser libraries
- Runtime environment can reach internal networks or cloud metadata
Quick version check:
npm ls axios
# or
pnpm ls axios
The fix is upgrading to axios@1.15.0 or later.