CVE-2026-44490: Axios: DoS & Header Injection via Prototype Pollution Read-Side Gadgets in axios merge functions

Published May 29, 2026
·
Updated

Summary

axios 1.15.2 exposes two read-side prototype-pollution gadgets. When Object.prototype is polluted by an upstream dependency in the same process (e.g. lodash .merge / CVE-2018-16487), axios silently picks up the polluted values:

1. Header injection - lib/utils.js line 406 builds merge()'s accumulator as result = {}, so result[targetKey] (line 414) walks Object.prototype and the polluted bucket's own keys are copied into the merged headers and ride out on the wire. 2. Crash DoS - lib/core/mergeConfig.js line 26 builds the hasOwnProperty descriptor as a plain-object literal. Object.defineProperty reads descriptor.get/descriptor.set via the prototype chain, so a polluted Object.prototype.get or Object.prototype.set makes the call throw TypeError synchronously on every axios request.

Affected Properties

| Polluted slot | Effect | |---|---| | Object.prototype.common | injects headers on every method | | Object.prototype.delete / .head / .post / .put / .patch / .query | injects headers on the matching method | | Object.prototype.get | every axios request throws TypeError: Getter must be a function from mergeConfig.js:26 | | Object.prototype.set | every axios request throws TypeError: Setter must be a function from mergeConfig.js:26 |

Per-request headers (axios.request(url, { headers: {...} })) overwrite polluted entries. Polluting Object.prototype.get triggers the crash before any header is built.

Proof of Concept

javascript const axios = require('axios');

// Finding A - header injection Object.prototype.common = { 'X-Poisoned': 'yes' }; await axios.get('http://api.example.com/users'); // Wire request carries X-Poisoned: yes.

// Finding B - crash DoS Object.prototype.get = { something: 'anything' }; await axios.get('http://api.example.com/users'); // TypeError: Getter must be a function: #<Object> // at Function.defineProperty (<anonymous>) // at mergeConfig (lib/core/mergeConfig.js:26:10)

Impact

- Server hang (Content-Length: 99999): receiver waits for a body that never arrives. Affects requests with a body. - CL+TE conflict (Transfer-Encoding: chunked rides alongside axios's auto Content-Length): receiver rejects with 400 Bad Request. Affects requests with a body. - Response suppression (If-None-Match: ): receiver returns empty 304 Not Modified. Affects GET / HEAD. - Crash DoS (Object.prototype.get / .set): every axios request fails synchronously with TypeError, not AxiosError, so handlers filtering on error.isAxiosError mishandle the failure.

Attack Flow

mermaid flowchart TD ROOT["Polluted Object.prototype<br/>via upstream gadget (e.g. lodash &lt;= 4.17.10 .merge / CVE-2018-16487)<br/>axios &lt;= 1.15.2"]

ROOT --> CLASSA["A. Arbitrary HTTP Header Injection<br/>Polluted defaults.headers slot rides along on every outbound axios request"] ROOT --> CLASSB["B. Crash DoS via Object.prototype.get / .set<br/>Polluted descriptor breaks Object.defineProperty in mergeConfig"]

CLASSA --> PREA["Precondition: header not set per-request by the app<br/>Injected via defaults.headers slot<br/>(common, delete, head, post, put, patch, query)"]

PREA --> PA1["Response Suppression<br/>Trigger: common = {If-None-Match: }<br/>Affects GET / HEAD"] PA1 --> SA1["DoS<br/>304 Not Modified empty"]

PREA --> PA2["Server Hang<br/>Trigger: common = {Content-Length: 99999}<br/>Affects requests with body"] PA2 --> SA2["DoS<br/>connection hang"]

PREA --> PA3["CL+TE Conflict<br/>Trigger: common = {Transfer-Encoding: chunked}<br/>Affects requests with body"] PA3 --> SA3["DoS<br/>400 Bad Request"]

CLASSB --> SB1["DoS<br/>TypeError: Getter / Setter must be a function<br/>Crashes every axios request, not only GET"]

%% Styles style ROOT fill:#f87171,stroke:#991b1b,color:#fff style CLASSA fill:#fb923c,stroke:#9a3412,color:#fff style CLASSB fill:#fb923c,stroke:#9a3412,color:#fff style PREA fill:#e2e8f0,stroke:#64748b,color:#1e293b style PA1 fill:#fbbf24,stroke:#92400e,color:#000 style PA2 fill:#fbbf24,stroke:#92400e,color:#000 style PA3 fill:#fbbf24,stroke:#92400e,color:#000 style SA1 fill:#ef4444,stroke:#991b1b,color:#fff style SA2 fill:#ef4444,stroke:#991b1b,color:#fff style SA3 fill:#ef4444,stroke:#991b1b,color:#fff style SB1 fill:#ef4444,stroke:#991b1b,color:#fff

Root Cause

Finding A. lib/utils.js:404-429's merge() creates result = {} at line 406. The dangerous-keys filter on lines 408-411 blocks the write side, but the read at line 414 (isPlainObject(result[targetKey])) still walks the prototype chain. When targetKey matches a polluted slot, result[targetKey] returns the polluted nested object, and the recursive merge(result[targetKey], val) on line 415 iterates that object's own keys via forEach and copies them as own properties into the new accumulator. Those keys flow through mergeConfig.js:35 → Axios.js:148 (utils.merge(headers.common, headers[config.method])) → Axios.js:155 (AxiosHeaders.concat(...)) → onto the wire via http.js:677 (headers: headers.toJSON()) → http.js:767 (transport.request(options, ...)).

Finding B. lib/core/mergeConfig.js:25 correctly makes config = Object.create(null), but the descriptor passed on line 26 is a plain-object literal - its get/set lookups walk Object.prototype. A polluted non-function Object.prototype.get or .set makes Object.defineProperty throw TypeError: Getter must be a function (or Setter must be a function) before the call returns. The descriptor is built unconditionally on every mergeConfig invocation, so every axios request throws - POST, PUT, DELETE, PATCH, HEAD, QUERY, not only GET.

Suggested Fix

Use null-prototype objects in place of the plain-object literals at lib/utils.js:406 and lib/core/mergeConfig.js:26-31. The same descriptor pattern recurs at lib/core/AxiosError.js:37, lib/core/AxiosHeaders.js:100, lib/utils.js:447/454/492/498, and lib/adapters/adapters.js:28/32.

Resources

- CVE-2018-16487 - lodash.merge prototype pollution in lodash <= 4.17.10 - CWE-1321 - Improperly Controlled Modification of Object Prototype Attributes

Other sources

Axios is a promise based HTTP client for the browser and Node.js. Prior to 0.32.0 and 1.16.0, axios exposes two read-side prototype-pollution gadgets. When Object.prototype is polluted by an upstream dependency in the same process (e.g. lodash .merge / CVE-2018-16487), axios silently picks up the polluted values. (1) lib/utils.js line 406 builds merge()'s accumulator as result = {}, so result[targetKey] (line 414) walks Object.prototype and the polluted bucket's own keys are copied into the merged headers and ride out on the wire. (2) lib/core/mergeConfig.js line 26 builds the hasOwnProperty descriptor as a plain-object literal. Object.defineProperty reads descriptor.get/descriptor.set via the prototype chain, so a polluted Object.prototype.get or Object.prototype.set makes the call throw TypeError synchronously on every axios request. This vulnerability is fixed in 0.32.0 and 1.16.0.

MITRE

Affected Software

5 affected componentsFixes available
npm/axios<=0.31.1
0.32.0
npm/axios>=1.0.0<1.16.0
1.16.0
Axios Axios Node.js<0.32.0
Axios Axios Node.js>=1.0.0<1.16.0
IBM API Connect<=V10.0.8.0 - V10.0.8.9

Remediation

Recommended actions to resolve this vulnerability, in priority order.

  1. Upgrade

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

    Fixed in 0.32.0
  2. Upgrade

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

    Fixed in 1.16.0
  3. Upgrade

    Upgrade axios to a version that resolves this vulnerability.

    Fixed in 0.32.0
  4. Upgrade

    Upgrade axios to a version that resolves this vulnerability.

    Fixed in 1.16.0
  5. Configuration

    In the merge() function, replace the plain-object accumulator created at lib/utils.js line 406 (`result = {}`) with a null-prototype object so prototype chain lookups cannot be walked (the text says to use null-prototype objects instead of the plain-object literals at lib/utils.js:406).

    axios/lib/utils.js (merge) result accumulator initialization (line 406) = result = {} -> use null-prototype objects
  6. Configuration

    In mergeConfig (lib/core/mergeConfig.js:25-31), build the `hasOwnProperty` descriptor using a null-prototype object instead of a plain-object literal (the text specifically calls out lib/core/mergeConfig.js line 26-31 and says to use null-prototype objects in place of the plain-object literals at lib/core/mergeConfig.js:26-31).

    axios/lib/core/mergeConfig.js hasOwnProperty descriptor construction (line 26) = plain-object literal -> null-prototype object

Event History

May 29, 2026
Advisory Published
via GitHub·03:54 PM
Data Sourced
via GitHub·03:54 PM
DescriptionSeverityWeaknessAffected Software
Jun 11, 2026
CVE Published
via MITRE·03:36 PM
Data Sourced
via MITRE·03:36 PM
DescriptionSeverityWeakness
Data Sourced
via NVD·05:16 PM
DescriptionSeverityWeaknessAffected Software
Jul 7, 2026
Data Sourced
via IBM·12:00 AM
DescriptionAffected Software

Parent advisories

This vulnerability appears in the following advisories.

Free Weekly Intel

Don't miss critical vulnerabilities

Join thousands of security professionals who receive our weekly digest of trending CVEs, zero-days, and exploited vulnerabilities.

No spam. Unsubscribe anytime.

Frequently Asked Questions

1

What is the severity of CVE-2026-44490?

The severity of CVE-2026-44490 is medium with a score of 4.8.

2

How do I fix CVE-2026-44490?

To mitigate CVE-2026-44490, update axios to the version that addresses the prototype pollution issue.

3

What software is affected by CVE-2026-44490?

CVE-2026-44490 affects the npm package axios, specifically version 1.15.2.

4

What type of vulnerabilities does CVE-2026-44490 involve?

CVE-2026-44490 involves prototype pollution vulnerabilities that can occur through affected dependencies.

5

Can CVE-2026-44490 lead to data exposure?

CVE-2026-44490 could potentially lead to unexpected application behavior but does not directly expose sensitive data.

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