---
id: "CVE-2026-101908"
page: "https://infrastack.ai/live/CVE-2026-101908"
kind: "vulnerability"
aliases: ["CVE-2026-101908", "GHSA-vh66-26gq-q6x8"]
title: "Axios: Prototype pollution gadget in fetch adapter can alter outbound requests"
severity: "medium"
cvss: 6.9
epss: 0.00471
exploited: false
status: "open"
category: "package"
products: [{"name": "axios", "note": ">=1.7.0", "fixed": [">=1.20.0"], "affected": ">= 1.7.0", "ecosystem": "npm"}, {"name": "axios", "fixed": ["1.20.0"], "affected": ">= 1.7.0, < 1.20.0", "ecosystem": "npm"}]
ecosystems: ["npm"]
tags: ["axios", "cwe-1321", "fetch-adapter", "node", "npm", "package"]
not_affected_if: ["axios-below-1.7.0", "no-fetch-adapter", "no-prototype-pollution", "node-http-adapter"]
published_at: "2026-09-16T09:02:29+00:00"
first_seen_at: "2026-11-09T22:53:18+00:00"
updated_at: "2026-11-09T23:00:38+00:00"
sources: [{"source": "ghsa-repo", "url": "https://github.com/axios/axios/security/advisories/GHSA-vh66-26gq-q6x8", "first_seen_at": "2026-11-09T22:53:18+00:00"}, {"source": "ghsa", "url": "https://github.com/advisories/GHSA-vh66-26gq-q6x8", "first_seen_at": "2026-11-09T22:57:50+00:00"}, {"source": "nvd", "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-101908", "first_seen_at": "2026-11-09T23:10:12+00:00"}]
exploit_sources: [{"type": "epss", "score": 0.00471, "url": "https://api.first.org/data/v1/epss?cve=CVE-2026-101908"}]
---

# Axios: Prototype pollution gadget in fetch adapter can alter outbound requests

Link for people: https://infrastack.ai/live/CVE-2026-101908 (this .md is for agents)

When the Axios fetch adapter runs, inherited properties on fetchOptions can override the request headers, so a process already affected by prototype pollution can make Axios send attacker-chosen headers such as Authorization while dropping the caller's headers. Axios does not create the pollution itself; it is a gadget that needs a separate prototype-pollution flaw first.

_Summary, check and fix written by a model from the sources; labelled as such._

## Affected

- npm:axios affected >= 1.7.0 fixed >=1.20.0
- npm:axios affected >= 1.7.0, < 1.20.0 fixed 1.20.0

## How to check

- Check the installed axios version with `npm ls axios`; affected versions are `>= 1.7.0, < 1.20.0`.
- Search your code for `adapter: 'fetch'` or a `fetchOptions` option passed to Axios requests.
- Confirm whether any code in the same process can write to `Object.prototype` (prototype pollution sources such as unsafe deep merge libraries).

## Fix

- axios: upgrade to `1.20.0` or later.

## Timeline

- 2026-11-09T22:53:18+00:00 ghsa-repo https://github.com/axios/axios/security/advisories/GHSA-vh66-26gq-q6x8
- 2026-11-09T22:57:50+00:00 ghsa https://github.com/advisories/GHSA-vh66-26gq-q6x8
- 2026-11-09T23:10:12+00:00 nvd https://nvd.nist.gov/vuln/detail/CVE-2026-101908

## Documents

- [advisory] Maintainer's advisory: github.com https://github.com/axios/axios/security/advisories/GHSA-vh66-26gq-q6x8
- [advisory] Maintainer's advisory: api.github.com https://api.github.com/repos/axios/axios/security-advisories/GHSA-vh66-26gq-q6x8
- [fix] Patch: github.com https://github.com/axios/axios/pull/11141
- [fix] Patch: github.com https://github.com/axios/axios/commit/d19040bda7a8be2f82c3c6e1a5bc03917daee39a
- [fix] Release: github.com https://github.com/axios/axios/releases/tag/v1.20.0

## From the sources

## Summary

Axios fetch adapter requests can be altered by inherited properties on `fetchOptions`. The adapter resolves method, headers, body, signal, and credentials into `resolvedOptions`, creates a `Request`, and then calls `fetch(request, fetchOptions)` instead of `fetch(request, resolvedOptions)`. In runtimes such as Node's undici-backed fetch, inherited `fetchOptions.headers` can override the headers already placed on the `Request`.

Axios does not create the prototype pollution source. This is a read-side gadget that becomes exploitable after same-process prototype pollution.

## Impact

An attacker with a prior prototype-pollution primitive can cause affected fetch-adapter requests to send attacker-controlled headers and drop caller-specified headers. This can affect authorization, cache behavior, metadata-service interactions, or application-specific header-based controls.

The issue is specific to fetch-adapter behavior and does not affect Node HTTP adapter requests.

## Affected Functionality

Affected:

- `adapter: 'fetch'`.
- Runtime environments where the fetch adapter is selected.
- Requests where `fetchOptions` is an object that does not have safe own values for sensitive fetch init fields.

Not affected:

- Node HTTP adapter.
- Requests that do not use the fetch adapter.
- Processes where `Object.prototype` is not polluted.

## Technical Details

`lib/adapters/fetch.js` builds:

```js
const resolvedOptions = {
  ...fetchOptions,
  signal: composedSignal,
  method: method.toUpperCase(),
  headers: toByteStringHeaderObject(headers.normalize()),
  body: data,
  duplex: 'half',
  credentials: isCredentialsSupported ? withCredentials : undefined,
};

request = isRequestSupported && new Request(url, resolvedOptions);

let response = await (isRequestSupported
  ? _fetch(request, fetchOptions)
  : _fetch(url, resolvedOptions));
```

The fallback path without `Request` uses `resolvedOptions`, but the `Request` path passes the original `fetchOptions` as the second argument to `fetch()`. That second argument can contain inherited properties from `Object.prototype`.

Local verification on axios `1.18.1` set `Object.prototype.headers = { Authorization: 'Bearer POLLUTED' }` and called the fetch adapter with `headers: { 'X-Good': 'yes' }, fetchOptions: {}`. The loopback server received `Authorization: Bearer POLLUTED` and did not receive `X-Good`.

## Proof of Concept of Attack

Constrained local demonstration:

```js
Object.prototype.headers = { Authorization: 'Bearer POLLUTED' };
try {
  await axios.get(url, {
    adapter: 'fetch',
    headers: { 'X-Good': 'yes' },
    fetchOptions: {}
  });
} finally {
  delete Object.prototype.headers;
}
```

Expected safe behavior is that the sanitized axios headers remain in force. Current behavior can use the inherited fetch init headers instead.

## Workarounds

Use the Node HTTP adapter for security-sensitive server-side requests until fixed. If the fetch adapter must be used, avoid passing empty `fetchOptions` objects in processes where prototype pollution is possible, and set explicit safe own values for fetch init fields.

<details>
  <summary><h3>Original report</h3></summary>
  
Hello, I’m not completely sure if this is something you’d consider a security issue, since it depends on prototype pollution happening somewhere else first, but I wanted to report it just in case.

I was testing the fetch adapter with polluted prototype values and found that `Object.prototype.headers` can change the request axios sends.

The issue seems to be in `lib/adapters/fetch.js`. Axios creates a `Request` with the resolved headers/method/body, but then sends it with `fetch(request, fetchOptions)`. With undici, if `fetchOptions` doesn’t have its own headers, an inherited `Object.prototype.headers` value can be used during the final fetch call.

I tested it with this:

```js
import http from 'node:http';
import axios from 'axios';

const server = http.createServer((req, res) => {
  res.end(JSON.stringify({
    authorization: req.headers.authorization || null,
    xGood: req.headers['x-good'] || null
  }));
});

await new Promise(resolve => server.listen(0, '127.0.0.1', resolve));
const { port } = server.address();

Object.prototype.headers = {
  Authorization: 'Bearer POLLUTED'
};

try {
  const res = await axios.get(`http://127.0.0.1:${port}/`, {
    adapter: 'fetch',
    headers: { 'X-Good': 'yes' },
    fetchOptions: {}
  });

  console.log(res.data);
} finally {
  delete Object.prototype.headers;
  server.close();
}
```

The result I get is:

```json
{
  "authorization": "Bearer POLLUTED",
  "xGood": null
}
```

So the polluted Authorization header is sent, and the normal axios header is not.

Changing the fetch call to pass the already resolved options fixes it for me:

```diff
- _fetch(request, fetchOptions)
+ _fetch(request, resolvedOptions)
```

`resolvedOptions` already includes `...fetchOptions`, so custom fetch options should still work, while headers, method, body, and signal stay as clean own values.
</details>

---

_Free to read, with fair use of about 60 pages a minute. For higher limits or API access: sales@infrastack.ai_
