high

CVE

CVE-2026-67320

CWE

CWE-200

Affected Surface

  • The npm package `axios` in versions `>= 0.31.1` and `< 0.33.0`
  • The npm package `axios` in versions `>= 1.15.2` and `< 1.18.0`
  • Node.js services using the HTTP adapter, including default server-side axios usage
  • Applications whose request interceptors clone config objects with patterns such as `{...config}` or `Object.assign({}, config)`
  • Processes already exposed to prototype pollution through another dependency, parser, or upstream bug

CVE-2026-67320 is not another generic “prototype pollution somewhere in JavaScript” warning. The interesting part is that axios had already added hardening specifically meant to keep polluted Object.prototype values out of request config. The bug is that an ordinary immutable request interceptor can undo that hardening by cloning the config back into a normal object before dispatch.

Once that happens, the Node HTTP adapter can read config.proxy through the prototype chain again. If another vulnerable component in the same process has already polluted Object.prototype.proxy, axios can silently route the outgoing request through an attacker-controlled proxy.

Affected package and versions

Affected npm package:

  • axios >= 0.31.1 and < 0.33.0
  • axios >= 1.15.2 and < 1.18.0

Patched versions:

  • axios 0.33.0
  • axios 1.18.0

This issue is limited to Node.js request paths that use axios’s HTTP adapter. The disclosure does not establish browser impact, and it does not establish HTTPS header or body disclosure under normal TLS validation. The highest-confidence impact is plaintext HTTP traffic in Node.js services.

That caveat matters, but it does not make the bug unimportant. Many internal services, CI helpers, webhooks, metadata fetchers, and service-to-service clients still use plaintext HTTP on local networks, sidecar links, or development infrastructure.

The exact hardening failure

Axios’s intended defense is sound in principle. During config merging, it creates a null-prototype object so inherited values from Object.prototype are not consulted:

const config = Object.create(null);

The problem is what happens next. Request interceptors run after that merge, and axios lets the interceptor return a replacement config object. A very common pattern looks like this:

api.interceptors.request.use((config) => ({
  ...config,
  headers: {
    ...config.headers,
    'X-App': 'demo'
  }
}));

That code is not obviously dangerous. It is the kind of immutable config transformation many teams prefer in production code. But {...config} turns the hardened null-prototype config back into a regular object whose prototype is Object.prototype.

Axios then dispatches that replacement object without re-hardening it.

Why the Node adapter becomes the sink

The important code-level sequence described in the advisory is:

mergeConfig()
  -> creates null-prototype config
request interceptor
  -> returns plain object clone
dispatchRequest()
  -> forwards cloned config without re-hardening
http adapter
  -> reads config.proxy
  -> inherited Object.prototype.proxy is now visible

The vulnerable adapter behavior is conceptually simple:

setProxy(
  options,
  config.proxy,
  protocol + '//' + parsed.hostname + (parsed.port ? ':' + parsed.port : '') + options.path
);

If config.proxy is not an own property anymore, that read can resolve to attacker-controlled prototype data.

What a real exploit chain looks like

The attack is not “axios alone gives remote code execution.” The realistic exploit chain is two-stage:

  1. some other package or parser bug in the process pollutes Object.prototype.proxy
  2. axios later re-exposes that property by cloning hardened config into a regular object

The polluted value can look like:

Object.prototype.proxy = {
  protocol: 'http',
  host: '127.0.0.1',
  port: 8080
};

With the interceptor pattern above in place, affected axios requests can be sent to the attacker’s proxy instead of the intended target.

Confirmed impact

The public proof of concept shows more than just redirection. For plaintext HTTP requests, the attacker-controlled proxy can observe:

  • explicit Authorization headers
  • axios-generated Basic auth derived from config.auth
  • request method
  • absolute URL
  • Host header
  • request body

The proxy can also return its own response body to axios, so the client thinks the target server responded when the proxy actually did.

Representative vulnerable output from the disclosure shows:

{
  "explicitResponse": {"server": "proxy"},
  "basicResponse": {"server": "proxy"},
  "postResponse": {"server": "proxy"},
  "targetHits": [],
  "proxyHits": [
    {
      "url": "http://127.0.0.1:40613/api/secret",
      "method": "POST",
      "authorization": "Bearer EXPLICIT_SECRET",
      "host": "127.0.0.1:40613",
      "body": "{\"secret\":\"request-body-secret\"}"
    }
  ],
  "finalConfigPrototype": "Object.prototype",
  "finalConfigHasOwnProxy": false
}

That result is exactly why the issue deserves its own article. The harmful transition is not abstract prototype pollution. It is a documented hardening boundary being undone by ordinary interceptor code.

When you are and are not exposed

The highest-risk conditions are:

  • Node.js runtime
  • axios HTTP adapter path
  • a request interceptor that returns a plain object clone
  • prior prototype pollution elsewhere in the process
  • no explicit own proxy: false or other safe own proxy value

Conditions that reduce or remove exposure include:

  • browser adapters
  • the fetch adapter in Node.js
  • returning the original hardened config object instead of a clone
  • cloning into a null-prototype object
  • an own proxy: false on the instance or request

But those are mitigations, not substitutes for patching. The affected versions should still be upgraded because teams rarely control every library in-process well enough to guarantee “no prototype pollution can ever happen first.”

Real-world places this matters

This is not limited to hand-written REST clients. The pattern shows up in:

  • API gateway and BFF services that add headers in interceptors
  • internal SDK wrappers that standardize auth and tracing metadata
  • webhook relays and service connectors that fetch attacker-influenced URLs
  • CI and deployment helpers that call internal HTTP services with bearer tokens
  • metadata harvesters and background jobs that still use plaintext HTTP on trusted networks

Those services often carry secrets that are far more valuable than the application payload itself.

Detection and scoping

Start with version inventory:

npm ls axios
pnpm why axios
yarn why axios

Then search for the risky adapter and interceptor patterns:

rg -n "interceptors\\.request\\.use|Object\\.assign\\(\\{\\}, config\\)|\\.\\.\\.config|adapter:\\s*['\"]http['\"]|proxy:\\s*false" src app lib packages scripts

The most important code review question is:

Can this process suffer prototype pollution from some other input path,
and do our axios interceptors return plain object clones?

If both answers are yes, vulnerable axios versions turn that combination into a request-redirection problem.

Remediation

Upgrade to a fixed version:

npm install axios@^1.18.0
# or, on the 0.x line:
npm install axios@^0.33.0

Then verify the resolved tree:

npm ls axios

If you cannot patch immediately, temporary risk reduction steps include:

  1. set an own proxy: false where proxy support is not needed
  2. avoid interceptors that clone config into ordinary objects
  3. prefer returning the original config object or a null-prototype clone
  4. use the fetch adapter where behavior is compatible and reviewed

Those steps reduce exposure, but they are brittle. The real fix is the patched axios release that restores the intended hardening guarantees.

Response guidance

If a service used vulnerable axios versions on the Node HTTP adapter and also had a reachable prototype-pollution path:

  1. review plaintext HTTP requests made during the exposure window
  2. rotate credentials that may have been present in axios headers or config.auth
  3. inspect outbound traffic for unexpected proxy routing
  4. review interceptor code that clones config objects

The deeper AppSec lesson is valuable beyond axios. Security controls implemented at “merge time” can be lost if later extension points rebuild objects without preserving the same invariants. In this case, the invariant was “config reads must not consult Object.prototype.” CVE-2026-67320 shows how one common {...config} pattern was enough to break it.

From research to remediation

Check whether this pattern exists in your codebase

Turn this research into a remediation workflow. Scan dependencies and package manifests for similar supply-chain risk, then prioritize fixes with reachability context.

References