GHSA-vh66-26gq-q6x8: Npm/axios vulnerability

Published Sep 30, 2026
·
Updated

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>

---

Affected Software

1 affected componentFixes available
npm/axios>=1.7.0<1.20.0
1.20.0

Remediation

Recommended actions to resolve this vulnerability, in priority order.

  1. Upgrade

    Upgrade npm/axios to a version that resolves this vulnerability.

    Fixed in 1.20.0
  2. Configuration

    Use the Node HTTP adapter for security-sensitive server-side requests instead of the fetch adapter until fixed.

    Axios adapter = Node HTTP adapter
  3. Configuration

    If the fetch adapter must be used, do not pass an empty fetchOptions object; set explicit safe own values for sensitive fetch init fields, including headers, method, body, signal, and credentials.

    Axios fetch adapter fetchOptions = Explicit safe own values for fetch init fields

Event History

Sep 30, 2026
Advisory Published
via GitHub·03:13 PM
Data Sourced
via GitHub·03:13 PM
DescriptionWeaknessAffected Software

Frequently Asked Questions

1

Who can exploit this issue?

An attacker needs a separate, prior prototype-pollution primitive in the same process. Axios is a read-side gadget in this scenario and does not itself provide the prototype-pollution source.

2

Which Axios requests are exposed?

Exposure is limited to requests using adapter: 'fetch' in environments where the fetch adapter is selected. Node HTTP adapter requests are not affected.

3

How can I determine whether an application is at risk?

Review whether the application uses the fetch adapter and whether untrusted input can first cause same-process prototype pollution. The relevant requests use a fetchOptions object without safe own values for sensitive fields such as headers, method, body, signal, or credentials.

Contact

SecAlerts Pty Ltd.
132 Wickham Terrace
Fortitude Valley,
QLD 4006, Australia
info@secalerts.co
By using SecAlerts services, you agree to our services end-user license agreement. This website is safeguarded by reCAPTCHA and governed by the Google Privacy Policy and Terms of Service. All names, logos, and brands of products are owned by their respective owners, and any usage of these names, logos, and brands for identification purposes only does not imply endorsement. If you possess any content that requires removal, please get in touch with us.
© 2026 SecAlerts Pty Ltd.
ABN: 70 645 966 203, ACN: 645 966 203