CVE-2026-101908 — axios
Fix: axios/axios@d19040bCVE-2026-101908 is a CWE-1321 vulnerability in axios. A fix is available for axios — see the affected versions and patch details below.
Axios: Prototype pollution gadget in fetch adapter can alter outbound requests
Exploitation Status
Proof-of-concept exploit code exists
- CISA’s SSVC triage found public proof-of-concept exploit code for this CVE, though no confirmed active exploitation.
Exploitation and automatability from CISA’s SSVC triage for CVE-2026-101908.
EPSS Exploitation Probability
Probability of exploitation in the next 30 days, from FIRST.org EPSS.
Real-World Exposure
axiosReal-time download stats are indexed for npm and PyPI packages. This vulnerability affects npm packages — download data is not available via public APIs for these ecosystems.
Description
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
fetchOptionsis 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.prototypeis not polluted.
Technical Details
lib/adapters/fetch.js builds:
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:
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.
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:
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:
{
"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:
- _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.
Affected Packages
| Ecosystem | Package | Vulnerable range | Fix |
|---|---|---|---|
| 📦npm | axios | ≥ 1.7.0&&< 1.20.0 | 1.20.0npm install axios@1.20.0 |
Detection & mitigation playbook
Open-source dependencyDetect
Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for axios, including transitive dependencies — a direct dependency you never call can still pull in a vulnerable version.
Fix
Update axios to 1.20.0 or later, then make sure no transitive (indirect) dependency still pins the vulnerable range — O3 confirms CVE-2026-101908 is resolved across your whole dependency graph.
Workarounds
If you can't upgrade right away: gate or disable the affected feature, validate untrusted input at the boundary, and avoid passing attacker-controlled data into the vulnerable path. O3's runtime protection blocks exploitation in production as an interim safeguard until the upgrade lands.
Fixing This On Your OS
If you run this on a Linux distribution, patch through your package manager against the distro's own security advisory below — it tracks the exact backported fix for your release, which can ship on a different timeline (and sometimes a different severity) than the upstream project.
| Product | Fixed in | Advisory |
|---|---|---|
| Red Hat Hardened Images | grafana13-1-main-13.1.6-0.6.hum1 | RHSA-2026:74869 |
| Red Hat Hardened Images | grafana12-4-main-12.4.12-0.3.hum1 | RHSA-2026:74871 |
| Red Hat Hardened Images | grafana13-2-main-13.2.1-0.9.hum1 | RHSA-2026:74872 |
Frequently Asked Questions
Is CVE-2026-101908 in your dependencies?
Find it across npm, including transitive dependencies.