CVE-2026-40175 Axios IMDS Bypass

Source: CVE-2026-40175: Axios Prototype Pollution → IMDSv2 Bypass + RCE — Nguyễn Anh Bình, omelet.tech blog

CVE-2026-40175 is a critical flaw in axios before 1.15.0, also tracked as GHSA-fvcv-3m26-pcqx with CVSS 10.0. It is a chain of three bugs, not one mistake in a single call. Prototype pollution in a dependency can inject a CRLF sequence when axios writes headers. That smuggled request can forge the PUT and the token header that IMDSv2 expects, then read the instance's temporary IAM credentials. Axios 1.15.0 rejects a header value that contains \r or \n. The callsite can be a hardcoded GET with no outside URL.

Overview

CVE-2026-40175 (GHSA-fvcv-3m26-pcqx, CVSS 10.0 Critical) is a vulnerability in axios < 1.15.0, the most popular HTTP client library for Node.js. It is not a single bug but a chain of 3 pieces. Prototype pollution in another library in the dependency tree leads to CRLF injection when axios writes headers to the socket. HTTP request smuggling can then forge both the PUT method and the header AWS IMDSv2 requires, and thereby steal the EC2 instance's temporary IAM credentials. Fixed in axios 1.15.0.

What Sets It Apart: No User Input Required

What makes this case notable is "Zero Direct User Input": the exploited code can be a completely hardcoded line that accepts no URL/header from outside (for example a single GET call to a fixed internal endpoint). The payload does not arrive through that request's parameters but through the prototype of Object, global state shared by every object in the process.

The Three Pieces of the Attack Chain

Prototype Pollution as Global "Ambient State"

Every object literal {} in JavaScript inherits from Object.prototype. If a function in the dependency tree merges external data into an object without filtering special keys (__proto__, constructor.prototype, and similar), an attacker can write directly into Object.prototype. Older versions of qs, minimist, ini, body-parser, and lodash.merge are examples. After that, every object in the entire process (even in completely unrelated modules) "inherits" the polluted property when it is enumerated/merged, including the headers object that axios builds in mergeConfig.

CRLF Injection → HTTP Request Smuggling

When writing header values to the socket, axios (before the patch) did not check whether the value contained \r\n. A polluted header value can contain a \r\n\r\n sequence followed by an entire valid second HTTP request. That second request includes a request line, Host, other headers, and another \r\n\r\n. When axios sends the request, the receiving side may treat it as two separate requests on the same connection. An intermediate proxy or service mesh that parses HTTP inconsistently can do the same. That is the CWE-444 class of bug. This is classic request smuggling, except the payload source is not user input but a polluted prototype.

Why IMDSv2 (Well Designed) Is Still Bypassed

IMDSv1 allowed fetching IAM credentials with a simple GET to 169.254.169.254, which was the cause of the 2019 Capital One data breach. IMDSv2 fixed this by requiring the client to first PUT /latest/api/token with the X-aws-ec2-metadata-token-ttl-seconds header to obtain a token. The design assumes that classic SSRF usually only forces the server to send a GET with headers chosen by the app itself. It cannot choose the PUT method or arbitrary headers.

The CVE-2026-40175 chain breaks exactly that assumption: because the attacker can smuggle an entire different HTTP request (method, arbitrary headers) via CRLF injection, they have enough "capability" to complete the PUT/token handshake IMDSv2 demands, which classic SSRF cannot do.

Quick Comparison

Aspect Classic SSRF CVE-2026-40175
User input needed at callsite? Yes No — code can be fully hardcoded
Control over HTTP method? GET only Any (PUT, DELETE...)
Control over header values? No Yes, via prototype pollution
Blocked by IMDSv2? Yes No
Vulnerability class (CWE) CWE-918 (SSRF) CWE-113 + CWE-444 + CWE-918 (chain)

The Patch

The fix in axios 1.15.0 essentially adds a single check: if a header value contains the \r or \n character, throw an error immediately instead of letting it through, which prevents stuffing a second request into a header value.

  • Upgrade axios to >= 1.15.0 right away; there are no significant breaking changes.
  • Limit the IMDS hop limit on EC2 instances to 1 (--http-put-response-hop-limit 1) so containers/network bridges cannot reach the metadata service across multiple hops.
  • If you already use IRSA (IAM Roles for Service Accounts) on EKS or equivalent, consider disabling IMDS entirely at the instance level.
  • Audit the dependency tree for libraries (older qs, lodash.merge, minimist, body-parser, ...) that still carry unpatched prototype pollution flaws; this is the prerequisite for the chain to work.
  • The risk is not limited to AWS: since the core is HTTP request smuggling, it also applies to cache poisoning, auth bypass, or targeting the metadata services of GCP/Azure.

References (from the Original Post)

  • GHSA-fvcv-3m26-pcqx — GitHub Security Advisory
  • axios v1.15.0 — patch commit and release notes
  • NVD — CVE-2026-40175
  • AWS — IMDSv2 documentation: defense in depth against open firewalls/reverse proxies/SSRF
  • CWE-113 (HTTP Response Splitting), CWE-444 (Inconsistent Interpretation of HTTP Requests / Smuggling)

See also: Security Tools · Authentication Security