chore(deps): update dependency axios to v1.20.0 [security] - #1875
renovate[bot] wants to merge 1 commit into
Conversation
|
Important Review skippedAuto reviews are limited based on label configuration. 🏷️ Required labels (at least one) (1)
Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository: Zoo-Code-Org/Zoo-Code/.coderabbit.yaml Review profile: ASSERTIVE Plan: Advanced Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Review statusThis PR was opened by an automated account. A human maintainer must verify the change intent, provenance, and validation before merging. Current step: Awaiting fresh human maintainer or CODEOWNER approval. Review-state labels are managed by this workflow; do not edit them manually. |
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
This PR contains the following updates:
1.18.1→1.20.0Axios: Denial of Service via Unhandled 'error' Event in HTTP/2 ClientHttp2Session Initialization
CVE-2026-101901 / GHSA-542g-h47m-68v8
More information
Details
Summary
Axios versions with Node.js HTTP/2 support can terminate the caller’s process when a ClientHttp2Session emits an error event that is not handled by axios.
This affects applications that use the Node HTTP adapter with httpVersion: 2. A malicious, unavailable, or non-HTTP/2 endpoint can cause an uncaught exception instead of a normal rejected axios request.
Impact
The impact is denial of service. In affected applications, an attacker who can influence the request destination, or operate the destination server, may be able to crash the Node.js process.
This does not affect default HTTP/1.1 usage, browser XHR/fetch adapters, or applications that do not enable axios HTTP/2 support.
Affected Functionality
Affected path:
Caller-controlled http2Options can make the issue easier to trigger, but passing arbitrary attacker input into axios config is caller-controlled behavior and should not be the primary advisory framing.
Technical Details
Http2Sessions.getSession() creates a session with http2.connect(authority, options) but only registers a close handler. It does not register an error handler on the returned ClientHttp2Session.
When the session emits error, Node treats it as an unhandled EventEmitter error and throws. This can bypass the normal axios Promise rejection path and terminate the process.
Proof of Concept of Attack
Expected vulnerable behavior: the process exits with an uncaught ECONNREFUSED session error instead of only rejecting the axios request.
Workarounds
Disable axios HTTP/2 for untrusted or user-influenced destinations and use the default HTTP/1.1 adapter until a fixed release is available. Also avoid passing attacker-controlled values into http2Options; axios config is trusted application input.
Original report
Hi, i'm RelunSec a security researcher working with InsiteTech.jp
i want let you known, i finded a DoS in axios, to reproduce that, that is the example of a server
i tested all that in latest git version, after starting the server.cjs, to trigger that you just need do
that is extremly simple to trigger
it confirms a DoS in the HTTP/2 session cache, that needs be patched, the impact is will lead the server crashes and shutdown by an attacker, the server is written properly and no flaws in it and try catch blocks and errors handled however because that is an axios internal error will crash
Severity
CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:NReferences
This data is provided by the GitHub Advisory Database (CC-BY 4.0).
Axios: HTTP/2 adapter bypasses configured DNS lookup and proxy controls
CVE-2026-101898 / GHSA-3pq3-5fj3-cg6v
More information
Details
Summary
Axios for Node.js does not apply configured DNS lookup or proxy controls when a request uses
httpVersion: 2. The HTTP/1 adapter path wraps and forwardsconfig.lookup, builds normal request options, and applies proxy routing throughsetProxy(). The HTTP/2 path builds a session withhttp2.connect()using onlyoptions.http2Options, which drops the top-levellookup,agent, and proxy state.Applications are affected when they allow a user to influence request destinations, enable axios HTTP/2, and rely on axios
lookupor proxy routing to prevent SSRF or enforce outbound network policy.Impact
In affected server-side deployments, an attacker can cause axios to connect directly to destinations that the configured resolver or proxy would have rejected. Depending on reachable services, this can expose cloud metadata, internal service responses, or allow state-changing requests to internal systems.
This is not an unconditional SSRF in every axios deployment. It requires
httpVersion: 2and an application-level trust boundary where user-influenced URLs are constrained bylookupor proxy policy.Affected Functionality
Affected:
httpVersion: 2.config.lookupsupplied as a DNS policy.config.proxyand environment-derived proxy settings for HTTPS HTTP/2 requests.Not affected:
lookupto the transport and apply proxy handling.Technical Details
In
lib/adapters/http.js, the adapter readslookup, wraps it, stores it on the requestoptions, and appliessetProxy()before selecting a transport. For HTTP/2,http2Transport.request()builds an authority fromoptions.protocol,options.hostname, andoptions.port, then calls:lib/helpers/Http2Sessions.jsultimately callshttp2.connect(authority, options)with only thehttp2Optionsobject. The configured DNS lookup and the proxy or tunneling agent installed on the top-level request options are not forwarded into that call.Local verification on axios
1.18.1showedlookupCalls: 0while an HTTP/2 request to a local h2 origin succeeded. A second local HTTPS h2 verification with an explicit rejecting HTTP proxy showed the origin received the request and the proxy observed no traffic.Proof of Concept of Attack
Local constrained demonstration:
axios.get("http://localhost:<port>/internal", { httpVersion: 2, lookup })wherelookupthrowsEPOLICY.0.For proxy routing:
httpVersion: 2,http2Options: { rejectUnauthorized: false }, and explicitproxy.Expected safe behavior is that either the lookup policy blocks the request or the proxy observes and rejects the request.
Workarounds
Use the HTTP/1 adapter path for requests that depend on axios
lookupor proxy controls. Alternatively, enforce destination allow/deny policy before calling axios, outside the adapter transport path.Original report
Summary
I found that Axios does not apply the configured
lookupfunction or proxy when a request useshttpVersion: 2. The HTTP/1 adapter applies both controls, but the HTTP/2 path connects straight to the URL's hostname usinghttp2.connect().This matters for server applications that accept a user-influenced URL and use a custom DNS lookup or mandatory outbound proxy to prevent SSRF. Switching the Axios instance to HTTP/2 silently removes those controls, allowing the request to reach an address the application intended to block.
I reproduced this on the current npm release, Axios 1.18.1.
Details
The HTTP adapter reads and wraps the caller's
lookupfunction, builds the normal request options, and callssetProxy():lib/adapters/http.js, around lines 530-578: reads and wrapslookuplib/adapters/http.js, around lines 895-954: addslookuptooptionsand appliessetProxy()For HTTP/2, however, the adapter selects
http2Transport. That transport creates an authority from the destination and only passesoptions.http2Optionsto the session pool:lib/helpers/Http2Sessions.jsthen calls:At this point
optionsis only thehttp2Optionsobject. The top-levellookup, the proxy tunnelling agent created bysetProxy(), and the selectedhttpAgent/httpsAgentare not forwarded. The request therefore uses the system resolver and opens a direct connection to the origin.The same root cause affects both explicit proxy configuration and environment-derived proxy configuration. I kept the PoC local and used an explicit proxy so the result does not depend on shell environment variables.
PoC
I attached axios_http2_transport_controls_poc.mjs. The PoC is entirely local and sets up three pieces:
REACHED_BLOCKED_ORIGIN.502 Bad Gateway.lookupcallback that rejects every DNS lookup with anEPOLICYerror.The first request is an HTTP/1 control request. It uses the blocking
lookupcallback and has proxying disabled. Axios calls the callback, receivesEPOLICY, and does not reach the origin. This confirms that the callback works and that the hostname is blocked through the normal adapter path.The second request targets the same URL with
httpVersion: 2. It is given both security controls: the same blockinglookupcallback and the rejecting proxy. If Axios honors either one, this request cannot reach the origin. It should fail withEPOLICY, or it should reach the proxy and receive its502response.Instead, the request returns HTTP 200 with
REACHED_BLOCKED_ORIGIN. The lookup counter does not increase, and the proxy records no request or CONNECT attempt. The origin is the only server that records traffic. This shows that the HTTP/2 path skipped both controls and connected directly using the system resolver.To reproduce, run the attachment from the root of an Axios checkout:
Run it from the root of an Axios checkout:
Relevant output from my run:
{ "axiosVersion": "1.18.1", "configuredControls": { "lookup": "reject every DNS lookup with EPOLICY", "proxy": "http://127.0.0.1:<port> (reject every request)" }, "http1Control": "EPOLICY: blocked by application DNS policy", "http2Result": { "status": 200, "data": "REACHED_BLOCKED_ORIGIN" }, "lookupCalls": 1, "proxyObservedTraffic": false, "events": [ { "server": "origin", "protocol": "h2", "path": "/internal" } ] }The important parts of the output are:
http1ControlcontainsEPOLICY, proving the DNS policy blocks the destination under HTTP/1.lookupCallsis still1after both requests, proving HTTP/2 never called the configured resolver.proxyObservedTrafficisfalse, proving HTTP/2 did not use the configured proxy.http2Result.statusis200, and the sole event belongs to the origin, proving Axios connected directly to the blocked destination.Impact
The vulnerable configuration is a Node.js application that:
httpVersion: 2;lookupoption or proxy routing to enforce a destination or egress policy.In that setup, an unauthenticated application user may be able to make the server connect directly to loopback, private-network, or link-local services that the lookup policy or proxy would have rejected. Depending on the reachable service, this can expose cloud credentials or internal data, modify internal services, or affect availability.
HTTP/2 support is marked experimental, but neither the HTTP/2 documentation nor the proxy documentation says that
lookupand proxy controls are ignored. The proxy documentation states that HTTPS requests are sent through a CONNECT tunnel. More importantly, Axios's threat model tells callers that destination validation is their responsibility; this behavior silently bypasses such caller-supplied validation.I did not test against any third-party or production service. The PoC only uses listeners on my own machine.
Severity
CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:N/VI:N/VA:N/SC:H/SI:H/SA:NReferences
This data is provided by the GitHub Advisory Database (CC-BY 4.0).
Axios: Prototype Pollution Gadget in axios toFormData Options
CVE-2026-101909 / GHSA-x97p-jq2g-jp4f
More information
Details
Summary
Axios form serialization reads
visitor,maxDepth,dots,indexes,metaTokens, andBlobfrom an internal options object without own-property guards. WhenObject.prototypehas been polluted elsewhere in the same process, those inherited values can change how axios serializes multipart and URL-encoded request bodies.Axios does not create the prototype pollution source. This is a read-side gadget: axios turns an existing same-process pollution condition into altered request serialization or request failures.
Impact
The impact depends on which property is polluted and which axios serialization path the application uses.
Polluted
dots,indexes, ormetaTokenscan change field names and cause the receiving service to parse different data than the caller intended. PollutedmaxDepthcan cause nested form submissions to throwERR_FORM_DATA_DEPTH_EXCEEDED, producing request-level or service-level denial of service for affected workflows. Pollutedvisitorcan execute as the serializer visitor if an attacker can place a function onObject.prototype, but that condition generally implies a stronger same-process code-execution or malicious-dependency primitive and should be described carefully.Affected Functionality
Affected:
axios.toFormData().transformRequestpaths that serialize plain objects tomultipart/form-data.formSerializeroption defaults when the relevant properties are absent as own properties.Not affected:
toFormData().Object.prototypeis not polluted.Technical Details
lib/helpers/toFormData.jsmerges caller options with defaults usingutils.toFlatObject(). Whenoptionsisundefined,toFlatObject()returns the default object unchanged:That default object has
Object.prototypein its prototype chain.toFormData()then reads behavior-affecting values directly:These reads can resolve inherited polluted properties.
Local code review confirmed the direct reads in
v1.18.1. Tag checks show the option-based form serializer exists inv0.28.0and later;maxDepthappears in the1.xline from the form recursion fix.Proof of Concept of Attack
Constrained local demonstration:
Expected safe behavior is that the default max depth is used unless the caller sets an own
formSerializer.maxDepth. Current behavior reads the inherited value and can throwERR_FORM_DATA_DEPTH_EXCEEDED.For serializer alteration, polluting
Object.prototype.dots = truechanges nested field naming from bracket notation to dot notation when the caller did not opt into that behavior.Workarounds
Avoid serializing attacker-controlled objects as form data in a process with known prototype pollution. As a partial mitigation, callers can pass an own
formSerializerobject that sets explicit safe values for all relevant keys, includingvisitor,maxDepth,dots,indexes,metaTokens, andBlob.Original report
Summary
axios v1.18.1 contains a read-side prototype pollution gadget in its form data serialization logic. Six option properties (
visitor,maxDepth,dots,indexes,metaTokens,Blob) are read from a plain JavaScript object that inherits fromObject.prototypewithouthasOwnPropertyguards. WhenObject.prototypehas been polluted elsewhere in the process a common consequence of compromised transitive npm dependencies, these polluted values silently control axios' form serialization behavior.The highest-impact gadget is
visitor: a polluted function onObject.prototype.visitoris invoked for every key-value pair during multipart and URL-encoded form serialization, receiving the value, key, path, and internal helper functions as arguments.Details
Root Cause
The attack chain has three steps:
Step 1:
formSerializeris read safely, butundefinedflows throughIn
lib/defaults/index.js, the defaulttransformRequestfunction readsformSerializerfrom config using theown()helper, which enforceshasOwnProp:When the user does not explicitly configure
formSerializer, this correctly returnsundefined. Thatundefinedis then passed as theoptionsparameter totoFormData():Step 2:
toFlatObjectreturns a plain-object defaultInside
lib/helpers/toFormData.js,options(which isundefined) is merged with defaults viautils.toFlatObject():toFlatObjecthas an early-return for null/undefined sources:Since
optionsisundefined, the function returnsdestObjunchanged — the plain object{ metaTokens: true, dots: false, indexes: false }. This object's prototype isObject.prototype.Step 3: Options are read without
hasOwnPropguardsThe six option properties are read directly from the plain object:
None of these reads use
utils.hasOwnProp(). Since theoptionsobject inherits fromObject.prototype, any property set onObject.prototypeby a compromised dependency is resolved through the prototype chain.Why the Existing Defenses Didn't Catch This
axios has extensive prototype pollution defenses. However, those defenses are all focused on the config object (created by
mergeConfig, which returnsObject.create(null)). ThetoFormDatafunction creates its own internal options object that sits outside that boundary, and the 6 reads on that internal object were never audited.PoC
Reproduction Steps
Environment
Any environment with Node.js and npm. Tested on:
- Node.js v24.15.0, npm 11.13.0
- axios v1.18.1 (latest release at time of writing)
Step 1: Create a fresh project
mkdir axios-pp-poc cd axios-pp-poc npm init -y npm install axios@1.18.1Step 2: Create the PoC file
Create
poc.mjswith the following content:Step 3: Run the PoC
Impact
1. Data Exfiltration via
visitor(Confidentiality: High)A polluted
Object.prototype.visitorfunction is called as the form data visitor:The attacker receives:
-
value— the raw value being serialized (passwords, tokens, PII, API keys)-
key— the field name-
path— the full path array (e.g.,['profile', 'address', 'street'])-
exposedHelpers— internal helpers includingdefaultVisitor,convertValue,isVisitableBy delegating to
helpers.defaultVisitor, the attack is completely transparent, the request succeeds normally and the server receives intact data. The exfiltration is invisible to both the caller and the server.2. Denial of Service via
maxDepth(Availability: Low)A polluted
Object.prototype.maxDepthof1or2causes any moderately nested form data request to throwERR_FORM_DATA_DEPTH_EXCEEDED. Applications that send nested objects as form data (common with APIs that acceptprofile[name],address[city], etc.) will experience mysterious failures.3. Data Corruption via
dots,indexes,metaTokens(Integrity: Low)Polluting these options changes the serialization format of form field names:
-
dots: true— changes bracket notation (user[name]) to dot notation (user.name)-
indexes: true— changes array serialization (items[]) to indexed (items[0],items[1])-
metaTokens: false— changesobj{}keys to raw json stringsThe server may misinterpret the submitted form data, leading to silent data corruption.
Severity
CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:N/VI:L/VA:H/SC:N/SI:N/SA:NReferences
This data is provided by the GitHub Advisory Database (CC-BY 4.0).
Axios: ReDoS (O(N²)) in shouldBypassProxy host normalization, reachable via untrusted redirect Location
CVE-2026-101906 / GHSA-mghh-pgcx-3jjj
More information
Details
Summary
Axios
shouldBypassProxy()normalizes hostnames withhostname.replace(/\.+$/, ''). For a hostname shaped as many dots followed by a non-dot, the anchored regex can perform quadratic backtracking. Because axios re-evaluates proxy bypass rules for redirected requests, a malicious server can trigger this synchronous work through a crafted redirectLocation.The issue affects Node.js applications that use environment proxy variables with
NO_PROXYand allow redirects.Impact
An attacker-controlled server can return a redirect whose hostname causes the axios process to spend significant CPU time in synchronous hostname normalization. During this time, the Node.js event loop is blocked and the application cannot handle other work on that thread.
This is an availability-only issue. It does not disclose request data or modify requests.
Affected Functionality
Affected:
HTTP_PROXYorHTTPS_PROXY.NO_PROXYorno_proxyset to a non-empty value.follow-redirects.Not affected:
proxy: false.NO_PROXYvalue.maxRedirects: 0, unless application code manually follows the malicious redirect and re-enters axios.Technical Details
lib/helpers/shouldBypassProxy.jscontains:When the hostname is
"." * n + "a", the$anchor causes the regex engine to retry the dot run from many positions before it fails.setProxy()invokesshouldBypassProxy(location)aftergetProxyForUrl(location)returns a proxy, including on redirect hops viabeforeRedirects.proxy.Local timing on axios
1.18.1showed increasing cost for crafted hostnames: about 1 ms at 1000 dots, 6.9 ms at 3000 dots, and 34.5 ms at 6000 dots. The growth is consistent with the submitted quadratic claim while avoiding long-running payloads.Proof of Concept of Attack
Constrained helper-level demonstration:
In the full adapter path, a malicious server can return that hostname in a
302 Locationheader while the client has proxy environment variables andNO_PROXYconfigured.Workarounds
Disable automatic redirects for requests to untrusted servers, or avoid environment proxy handling for those requests with
proxy: falsewhen appropriate. Operators can also avoid broad untrusted redirect-following in services where event-loop availability is critical.Original report
Summary
shouldBypassProxy normalizes a host with hostname.replace(/.+$/, ''). On a host of the shape (e.g. "." × 40000 + "a"), this anchored regex backtracks quadratically (O(N²)), synchronously starving the Node.js event loop. Because axios re-evaluates the proxy on every redirect using the new Location host, a malicious server can return a crafted 302 Location and freeze the client's event loop for seconds per redirect — a denial of service.
Details
PoC
Self-contained, no network — imports axios's own helper:
// node poc.mjs (run next to an axios install)
import sbp from './node_modules/axios/lib/helpers/shouldBypassProxy.js';
process.env.NO_PROXY = 'example.com';
for (const n of [5000, 10000, 20000, 40000]) {
const url = 'http://' + '.'.repeat(n) + 'a/'; // arrives as an untrusted 302 Location host
const t0 = process.hrtime.bigint();
sbp(url); // returns false (correct no-bypass) — but O(N^2) slow
console.log(
N=${n}: ${(Number(process.hrtime.bigint()-t0)/1e6)|0} ms);}
// Measured on 1.18.1: N=5000 ~43ms, 10000 ~160ms, 20000 ~618ms, 40000 ~2499ms; benign host ~0.05ms.
Driven through the real http-adapter __setProxy on the redirect path (setProxy(…, isRedirect=true)), a 10 ms timer fires 0 times during the ~2.4 s block at N=40000 — full event-loop starvation.
Impact
Denial of service (event-loop starvation) on any axios client that uses an environment proxy with NO_PROXY set and follows redirects, when a server it contacts returns a crafted redirect Location. No data exposure or RCE. Same impact class as the accepted DoS advisories GHSA-62hf-57xw-28j9 (toFormData recursion) and the maxContentLength response-size DoS.
Suggested fix
Replace the regex trailing-dot strip with a linear trim:
let end = hostname.length;
while (end > 0 && hostname.charCodeAt(end - 1) === 46 /* '.' */) end--;
hostname = hostname.slice(0, end);
Also drop the redundant second /.+$/ pass in PR #11029's normalizeIPAddress.
Severity
CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:NReferences
This data is provided by the GitHub Advisory Database (CC-BY 4.0).
Axios: ReDoS in fromDataURI data: URL parser freezes the Node event loop (DoS)
CVE-2026-101903 / GHSA-c29m-xwm3-cm6r
More information
Details
Summary
Axios for Node.js parses
data:URLs inlib/helpers/fromDataURI.js. The current RFC-2397 parser uses a regular expression whose media type groups allow/inside both sides of thetype/subtypematch. A malformeddata:URL containing many slashes and no comma forces the JavaScript regex engine to try many possible placements for the separator before failing.Applications are affected when they pass untrusted URL strings to axios and do not reject or constrain
data:URLs before axios parses them.Impact
An attacker can make the Node.js event loop spend significant synchronous CPU time parsing a single malformed URL. In a server that accepts a URL from an HTTP request and calls
axios.get(url), this can block unrelated requests and health checks until parsing completes.The issue is availability-only. It does not disclose data or modify requests.
Affected Functionality
Affected:
axios.get()or equivalent calls whereconfig.urlhas thedata:protocol.Not affected:
data:URLs before calling axios.0.xdata URL parser shape unless separately proven vulnerable.Technical Details
lib/helpers/fromDataURI.jscontains:The
[^,;]+groups include/, so a long string of slashes without a comma can be partitioned around the required\/in many ways before the match fails. The match runs before axios can apply request timeout behavior, sotimeoutdoes not mitigate the parsing pause.Local timing on axios
1.18.1with small payloads showed about 2.4 ms at 1000 slashes, 16.6 ms at 3000 slashes, and 71.5 ms at 6000 slashes, consistent with the submitted quadratic scaling while avoiding long-running payloads.Proof of Concept of Attack
Constrained helper-level demonstration:
The request fails after parsing, but the failure is delayed by synchronous regex work. Larger payloads increase the pause substantially.
Workarounds
Reject
data:URLs before passing untrusted input to axios, or enforce a strict maximum URL length for URL-fetching endpoints. Applications that do not needdata:URL support should deny that protocol explicitly.Original report
ReDoS in
fromDataURIdata: URL parser freezes the event loop (DoS)Affected
axios(Node.js http adapter)v1.x, current release line)lib/helpers/fromDataURI.jsIssue
fromDataURIparsesdata:URLs with this regex:The mediatype tokens
[^,;]+include/, so they can span multiple slashes ambiguously. Adata:URL made of many slashes with no comma forces the engine to try every way to place the single\/divider before failing — quadratic O(n²) backtracking. It runs synchronously on the main thread, so the whole Node event loop is frozen for the entire parse. Reachable through the public API on the Node http adapter (axios.get(url)); the browser fetch/xhr adapters are not affected because they do not callfromDataURI.A configured
timeoutdoes not help: the freeze happens during parsing, before any network timer can fire.PoC (minimal)
Lab results
Single-threaded "fetch a user-supplied URL" service (link-preview style) calling
axios.geton a JSON body{ "url": "..." }, withtimeout: 1000set.Scaling is clean O(n²) (constant k ≈ 5.6e-6 ms/byte², stable across sizes):
event loop BLOCKED for 6.30s)During the freeze the server answers nothing: a
/healthzliveness probe times out for the whole window, and the server's own event-loop monitor cannot even log until the parse finishes. In a run through an intercepting proxy, the proxy hit its 120 s upstream timeout and gave up, while the origin stayed pegged at 100% CPU on one core past that — client/proxy timeouts do not mitigate it.The attacker controls only the URL string and needs no auth. ~256 KB every ~6 min (≈ 0.7 bytes/sec) keeps a server permanently unavailable.
Impact
Unauthenticated remote denial of service. One small request takes a Node service fully offline for minutes; a trickle keeps it down indefinitely.
CVSS 3.1: 7.5 (High) —
AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H.Fix
RFC 2045 type/subtype tokens never contain
/. Excluding/from those two character classes removes the ambiguity and the backtracking:Worst-case parse drops from ~2600 ms to ~0.002 ms. All valid
data:URLs, including slashes in the body, parse identically.Severity
CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:NReferences
This data is provided by the GitHub Advisory Database (CC-BY 4.0).
Axios: Prototype-Pollution Gadget in the Default Instance Allows Inherited Object.prototype.method to Override HTTP Method
CVE-2026-101902 / GHSA-9fr6-4gfg-395g
More information
Details
Summary
Axios default-instance requests that omit an explicit method can read an inherited
methodvalue fromObject.prototype. If another vulnerability in the same process pollutesObject.prototype.method, calls such asaxios.request({ url })andaxios({ url })can send a state-changing HTTP method instead of the expected defaultGET.Axios does not create the prototype pollution source. This is a read-side gadget in axios request dispatch.
Impact
In an affected application with a separate prototype-pollution primitive, an attacker can change axios default-instance requests that omit
methodfromGETto methods such asDELETE,POST,PUT, orPATCH. The practical impact depends on the target endpoint and can include unintended writes, deletion, or other state changes.Method aliases such as
axios.get(url)and requests with an explicit ownmethodare not affected by the confirmed method path.Affected Functionality
Affected:
axios.request({ url }).axios({ url }).config.methodis provided.Not affected in the confirmed method PoC:
axios.get(url)and other method aliases.axios.request({ url, method: 'GET' }).axios.create().request({ url })when the created instance defaults are produced by currentmergeConfig()and do not inherit fromObject.prototype.Technical Details
lib/core/Axios.jssets the request method with:mergeConfig()now returns a null-prototype request config, soconfig.methodis safe fromObject.prototype. However, the default axios instance stores the module defaults object asthis.defaults, and that defaults object is a normal object. IfObject.prototype.methodexists,this.defaults.methodresolves to the polluted inherited value.Local verification on axios
1.18.1showed a default-instanceaxios.request({ url })request reaching a loopback server asDELETEafterObject.prototype.method = 'DELETE'.Proof of Concept of Attack
Constrained local demonstration:
Expected safe behavior is a
GETrequest. Current affected behavior sendsDELETEon the default instance when no method is provided.Workarounds
Use explicit method aliases such as
axios.get()or set an ownmethodon request configs. Avoid default-instance shorthand for requests in processes where prototype pollution is suspected or possible.Original report
Summary
Axios
1.17.0contains a read-side prototype-pollution gadget in the default Axios instance. If another vulnerability in the same Node.js process pollutesObject.prototype.method, default-instance calls such asaxios.request({ url })andaxios({ url })can be forced to use an attacker-controlled HTTP method, such asDELETE, instead of the expected defaultGET.Axios does not create the prototype pollution by itself. The issue is that Axios reads fallback values from
this.defaultswithout an own-property guard, allowing inherited values fromObject.prototypeto influence request behavior.This should be treated as a prototype-pollution gadget, not as a standalone prototype-pollution source. In other words, Axios is not the component that lets the attacker write to
Object.prototype; Axios is the component that becomes dangerous afterObject.prototypehas already been polluted by another bug in the same process.Details
The vulnerable fallback read is in
lib/core/Axios.js:The merged request
configis created as a null-prototype object inlib/core/mergeConfig.js:Therefore, when the caller does not provide
config.method, the fallback becomes:The default Axios instance uses the module defaults object. In the tested version, that defaults object is affected by inherited properties from
Object.prototype. IfObject.prototype.methodis polluted,this.defaults.methodresolves to that inherited value and Axios uses it as the request method.The same unsafe inherited-property pattern also affects
this.defaults.allowAbsoluteUrls, which can change how absolute URLs are combined withbaseURL.Proof of Concept
Access and Attack Conditions
No admin access is required for Axios itself. This is a library-level gadget.
The attacker must have an existing way to pollute
Object.prototypein the same Node.js process, for example through a separate prototype-pollution vulnerability in another dependency or application input path. Axios is the gadget that turns that pollution into dangerous HTTP request behavior.Required condition:
What Axios contributes:
What Axios does not do:
Affected usage:
Not affected in the confirmed PoC:
Reproduction Steps
1.17.0:Object.prototype.method = "DELETE", default-instance calls that omit an explicit method are sent asDELETE.What the Method PoC Script Does
The PoC starts a temporary local HTTP server for each Axios call and records the HTTP method received by that server. It then simulates an already-existing prototype-pollution condition by setting:
While that pollution is active, the script sends five Axios requests:
The script then deletes the polluted property:
Finally, it prints the method observed by the local server for each request. The vulnerable behavior is confirmed when the default Axios instance sends
DELETEforaxios.request({ url })andaxios({ url }), while the safe comparison paths still sendGET.Method Override PoC
Create
validate-prototype-method-gadget.mjs:Run:
Observed result:
The local server received:
This confirms that inherited
Object.prototype.methodcontrols the default method for vulnerable default-instance request paths.Supporting
allowAbsoluteUrlsGadget EvidenceThe same inherited-property issue affects
allowAbsoluteUrls.Create
validate-prototype-allowabsoluteurls-gadget.mjs: