CVE-2026-101908: Axios: Prototype pollution gadget in fetch adapter can alter outbound requests
Summary
Axios fetch adapter requests can be altered by inherited properties on fetchOptions. The adapter resolves method, headers, body, signal, and credentials into resolvedOptions, creates a Request, and then calls fetch(request, fetchOptions) instead of fetch(request, resolvedOptions). In runtimes such as Node's undici-backed fetch, inherited fetchOptions.headers can override the headers already placed on the Request.
Axios does not create the prototype pollution source. This is a read-side gadget that becomes exploitable after same-process prototype pollution.
Impact
An attacker with a prior prototype-pollution primitive can cause affected fetch-adapter requests to send attacker-controlled headers and drop caller-specified headers. This can affect authorization, cache behavior, metadata-service interactions, or application-specific header-based controls.
The issue is specific to fetch-adapter behavior and does not affect Node HTTP adapter requests.
Affected Functionality
Affected:
- adapter: 'fetch'. - Runtime environments where the fetch adapter is selected. - Requests where fetchOptions is an object that does not have safe own values for sensitive fetch init fields.
Not affected:
- Node HTTP adapter. - Requests that do not use the fetch adapter. - Processes where Object.prototype is not polluted.
Technical Details
lib/adapters/fetch.js builds:
js const resolvedOptions = { ...fetchOptions, signal: composedSignal, method: method.toUpperCase(), headers: toByteStringHeaderObject(headers.normalize()), body: data, duplex: 'half', credentials: isCredentialsSupported ? withCredentials : undefined, };
request = isRequestSupported && new Request(url, resolvedOptions);
let response = await (isRequestSupported ? fetch(request, fetchOptions) : fetch(url, resolvedOptions));
The fallback path without Request uses resolvedOptions, but the Request path passes the original fetchOptions as the second argument to fetch(). That second argument can contain inherited properties from Object.prototype.
Local verification on axios 1.18.1 set Object.prototype.headers = { Authorization: 'Bearer POLLUTED' } and called the fetch adapter with headers: { 'X-Good': 'yes' }, fetchOptions: {}. The loopback server received Authorization: Bearer POLLUTED and did not receive X-Good.
Proof of Concept of Attack
Constrained local demonstration:
js Object.prototype.headers = { Authorization: 'Bearer POLLUTED' }; try { await axios.get(url, { adapter: 'fetch', headers: { 'X-Good': 'yes' }, fetchOptions: {} }); } finally { delete Object.prototype.headers; }
Expected safe behavior is that the sanitized axios headers remain in force. Current behavior can use the inherited fetch init headers instead.
Workarounds
Use the Node HTTP adapter for security-sensitive server-side requests until fixed. If the fetch adapter must be used, avoid passing empty fetchOptions objects in processes where prototype pollution is possible, and set explicit safe own values for fetch init fields.
<details> <summary><h3>Original report</h3></summary> Hello, I’m not completely sure if this is something you’d consider a security issue, since it depends on prototype pollution happening somewhere else first, but I wanted to report it just in case.
I was testing the fetch adapter with polluted prototype values and found that Object.prototype.headers can change the request axios sends.
The issue seems to be in lib/adapters/fetch.js. Axios creates a Request with the resolved headers/method/body, but then sends it with fetch(request, fetchOptions). With undici, if fetchOptions doesn’t have its own headers, an inherited Object.prototype.headers value can be used during the final fetch call.
I tested it with this:
js import http from 'node:http'; import axios from 'axios';
const server = http.createServer((req, res) => { res.end(JSON.stringify({ authorization: req.headers.authorization || null, xGood: req.headers['x-good'] || null })); });
await new Promise(resolve => server.listen(0, '127.0.0.1', resolve)); const { port } = server.address();
Object.prototype.headers = { Authorization: 'Bearer POLLUTED' };
try { const res = await axios.get(http://127.0.0.1:${port}/, { adapter: 'fetch', headers: { 'X-Good': 'yes' }, fetchOptions: {} });
console.log(res.data); } finally { delete Object.prototype.headers; server.close(); }
The result I get is:
json { "authorization": "Bearer POLLUTED", "xGood": null }
So the polluted Authorization header is sent, and the normal axios header is not.
Changing the fetch call to pass the already resolved options fixes it for me:
diff - fetch(request, fetchOptions) + fetch(request, resolvedOptions)
resolvedOptions already includes ...fetchOptions, so custom fetch options should still work, while headers, method, body, and signal stay as clean own values. </details>
---
Other sources
Axios is a promise-based HTTP client for the browser and Node.js. From 1.7.0 until 1.20.0, the fetch adapter constructs a Request with sanitized resolvedOptions but then calls fetch with the original fetchOptions. A separate same-process prototype-pollution flaw populates Object.prototype.headers so fetchOptions.headers resolves through inheritance. The inherited fetchOptions.headers value overrides the sanitized Request headers through the second argument to fetch after Request construction. Attacker-controlled request headers can alter authorization, caching, metadata-service access, or application-specific behavior. This issue is fixed in version 1.20.0.
— NVD
Affected Software
Remediation
Recommended actions to resolve this vulnerability, in priority order.
- Upgrade
Upgrade
npm/axiosto a version that resolves this vulnerability.Fixed in 1.20.0 - Upgrade
Upgrade
axiosto a version that resolves this vulnerability.Fixed in 1.20.0 - Configuration
Use the Node HTTP adapter for security-sensitive server-side requests until upgrading to version 1.20.0.
Axios adapter = http - Configuration
If the fetch adapter must be used, avoid passing empty fetchOptions objects in processes where prototype pollution is possible, and set explicit safe own values for sensitive fetch init fields.
Axios fetch adapter fetchOptions = explicit safe own values for sensitive fetch init fields
Event History
Frequently Asked Questions
What conditions are required for exploitation?
An attacker must be able to exploit a separate prototype-pollution issue in the same process to populate Object.prototype.headers. The vulnerable fetch adapter must then make an outbound request using fetchOptions that inherits that attacker-controlled headers value.
Which Axios versions need remediation?
Axios versions from 1.7.0 up to, but not including, 1.20.0 are affected. Upgrade to version 1.20.0 to obtain the fix.
What can an attacker change through this issue?
Attacker-controlled inherited headers can override the sanitized headers when fetch is called. This can affect authorization, caching, metadata-service access, or application-specific behavior of outbound requests.