Repository navigation
chore(deps): update dependency axios to v1.20.0 [security] - #204
Open
renovate[bot] wants to merge 1 commit into
Open
renovate[bot] wants to merge 1 commit into
renovate[bot] wants to merge 1 commit into
Conversation
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR contains the following updates:
1.18.0→1.20.0Axios: maxRedirects: 0 is not enforced by the fetch adapter, allowing redirect-based SSRF
CVE-2026-101907 / GHSA-r4gj-5m52-g5wh
More information
Details
Summary
Axios exposes
maxRedirectsto limit redirect following, andmaxRedirects: 0is used by applications as a redirect-based SSRF guard. The Node HTTP adapter enforces this option. The fetch adapter does not read it and does not set a Fetch APIredirectmode, so the runtime default ofredirect: 'follow'applies.Applications are affected when they rely on
maxRedirects: 0and use the fetch adapter, either explicitly or because the runtime selects it.Impact
An attacker who controls the initial URL or a redirecting server can cause a fetch-adapter request to follow a redirect even though the caller configured
maxRedirects: 0. If the redirect target is reachable only from the application environment, this can expose internal responses or trigger state-changing internal endpoints.This should not be described as unconditional SSRF. The bypass requires a redirect source, such as an attacker-controlled server or open redirect, and an application that trusted
maxRedirects: 0as the redirect guard.Affected Functionality
Affected:
adapter: 'fetch'.maxRedirects: 0but withoutfetchOptions.redirect: 'manual'or equivalent runtime-specific redirect control.Not affected:
maxRedirects: 0.Technical Details
lib/adapters/fetch.jsdestructures many fields fromresolveConfig(config), but notmaxRedirects. It then builds fetch options without aredirectkey:Because
redirectis absent, the Fetch API default is to follow redirects.Local verification on axios
1.18.1showed the HTTP adapter throwing withmaxRedirects: 0, while the fetch adapter followed the same loopback302and returned the internal response.Proof of Concept of Attack
Constrained local demonstration:
302 Location: http://127.0.0.1:<server-b>/internal.INTERNAL.Workarounds
For fetch-adapter requests, set
fetchOptions: { redirect: 'manual' }where the runtime supports it, or use the Node HTTP adapter for requests that rely on axios redirect limits.Original report
Summary
Axios 1.17.0 exposes
maxRedirectsas a configuration option to limit redirect following, and setting it to0is a documented pattern for preventing redirect-based SSRF. The HTTP adapter enforces this viafollow-redirects. The fetch adapter does not readmaxRedirectsat all - it passes requests to the underlyingfetch()call with noredirectoption, which defaults to'follow', so redirects are followed by the runtime rather than being constrained by axiosmaxRedirects.In the attached PoC, a request issued with
maxRedirects: 0andadapter: 'fetch'follows a302redirect to an internal service and returns its response, while the same request withadapter: 'http'correctly throws. A second bypass case demonstrates that the redirect can reach a state-changing internal endpoint, not just read-only ones, proving both confidentiality and integrity impact.This affects any application that sets
maxRedirects: 0as a redirect guard and runs in an environment where the fetch adapter is active: Deno, Bun, Cloudflare Workers, or Node.js withadapter: 'fetch'set explicitly.Details
The fetch adapter destructures config fields from
resolveConfigatlib/adapters/fetch.js:The options object passed to
fetch()has noredirectkey:Because no
redirectkey is present, the Fetch API default ofredirect: 'follow'applies, so redirects are handled by the runtime rather than constrained by axiosmaxRedirects. The HTTP adapter, by contrast, delegates tofollow-redirects, which readsmaxRedirects, enforces the cap, and stripsAuthorization,Cookie, andProxy-Authorizationon cross-origin redirects.The discrepancy between adapters is not documented. The threat model covers credential stripping on redirects (T-R2) and cites
follow-redirectsas the mitigation, but makes no mention that the fetch adapter does not participate in this mitigation. See: https://github.com/axios/axios/blob/master/THREATMODEL.md#t-r2-credential-leakage-on-cross-origin-redirectThe behaviour difference between adapters is summarised below:
config.maxRedirectsmaxRedirects: 0Authorizationcross-originfollow-redirects>=1.15.8)Cookiecross-originWhen is the fetch adapter selected?
httpmodule available; the adapter list falls through to'fetch'axios.get(url, { adapter: 'fetch' })axios.create({ adapter: ['fetch'] })PoC
Run:
Observed:
Control
Axios does correctly enforce
maxRedirects: 0in the HTTP adapter. The[CONTROL]case above confirms this: the same request withadapter: 'http'throws rather than following the redirect, and the internal hit counter stays at0:The issue is not that
maxRedirectsis broken globally. It is enforced correctly for the HTTP adapter. The bypass is specific to the fetch adapter, which never reads the option and passes noredirectconstraint to the underlyingfetch()call.Impact
This is a redirect enforcement bypass affecting axios applications running in environments where the fetch adapter is active.
The internal admin route in the PoC simulates an affected deployment where a redirected request can reach state-changing internal APIs. The vulnerability is that
maxRedirects: 0is silently ignored by the fetch adapter; the exact impact depends on what redirect targets are reachable from the runtime.The impact is environment- and configuration-dependent. It affects axios users who:
maxRedirects: 0as a defense against redirect-based SSRF, andIn these cases, a
302redirect from the initial target is followed silently by default, unless the caller separately setsfetchOptions.redirect. If the redirect target is an internal service, the application returns its response to the caller with no indication that a redirect occurred or thatmaxRedirectswas not honoured. The failure is silent: no error is thrown, no warning is logged.The bypass is not limited to read-only access. As demonstrated by the second bypass case, a redirect to a state-changing internal endpoint succeeds equally. An attacker who can influence the redirect destination, for example through an open redirect on the initial target or a server they control, can reach internal and trigger mutations that the application never intended to issue.
Potentially affected environments include:
httpmodule.adapter: 'fetch'or a custom adapter list that resolves to fetch.maxRedirects: 0and runs across multiple environments with different adapter selection.Internal services reachable via a redirect include cloud instance metadata endpoints (
169.254.169.254), unauthenticated local services such as Redis or internal admin APIs, and other hosts accessible from the application's network that are not intended to be reachable by the caller. The hit counter in the PoC makes the access concrete:0after the HTTP control,1after the confidentiality bypass,2after the integrity bypass.This should not be characterised as an unconditional SSRF. The bypass requires either an open redirect on the initial target, or a URL that is itself a redirect. The issue is that
maxRedirects: 0, which is the intended mitigation for this class of attack, is silently non-functional in the fetch adapter, leaving applications with a false sense of protection.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: 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 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: Node HTTP adapter prototype-pollution gadget allows request socket hijack via inherited createConnection
CVE-2026-101905 / GHSA-m8m8-qj5v-23w3
More information
Details
Summary
Axios' Node HTTP adapter can act as a read-side prototype-pollution gadget for Node's sensitive
createConnectionrequest option. The adapter creates a null-prototype options object, but Node's HTTP client can copy or normalize request options into ordinary objects before connection creation. IfObject.prototype.createConnectionhas been polluted elsewhere in the same process, Node can call the inherited function and create a socket to an attacker-controlled endpoint.Axios does not create the prototype pollution source. The vulnerability is that axios does not set an own safe value for a sensitive transport option before handing options to Node.
Impact
Given a prior same-process prototype-pollution primitive, an attacker can redirect later axios Node HTTP requests at the socket layer while the request URL and axios config still appear to target the legitimate origin. The attacker-controlled endpoint can receive request headers and bodies, including Authorization headers, cookies, API keys, and service credentials, and can return attacker-controlled responses to the application.
This can bypass application destination validation that checks the URL before calling axios, because the URL remains legitimate while the underlying socket goes elsewhere.
Affected Functionality
Affected:
createConnection.Object.prototype.createConnectionis polluted.Not affected:
createConnectionand sanitizes options internally.Technical Details
lib/adapters/http.jscreates:The object does not include an own
createConnectionproperty. Local verification on axios1.18.1pollutedObject.prototype.createConnectionto connect to an attacker loopback server. A request to a legitimate loopback server with an Authorization header returned the attacker's response; the legitimate server received no request and the attacker server receivedBearer SECRET.Proof of Concept of Attack
Constrained local demonstration:
Expected safe behavior is that the legitimate server receives the request. Current affected behavior lets the attacker server receive the request and return the response.
Workarounds
Run axios in a process where prototype pollution is not present. For high-risk internal clients, use a custom trusted transport or agent layer that sets and enforces its own connection creation behavior instead of allowing inherited Node request options to participate.
Original report
Summary
Axios' Node HTTP adapter remains exploitable as a read-side prototype-pollution gadget after the recent null-prototype hardening. This is not a claim that axios creates the prototype pollution source. The precondition is a separate upstream prototype pollution primitive in the same Node.js process.
When
Object.prototype.createConnectionis polluted, axios requests can be redirected to an attacker-controlled socket even though the adapter builds the request options withObject.create(null). The request URL and axios config still appear to target the legitimate host, but the actual socket is attacker-controlled.This allows credential exfiltration and response manipulation for later axios HTTP requests in a polluted process.
Impact
Given an upstream prototype pollution primitive in the same process, an attacker can turn later axios HTTP requests into a man-in-the-middle primitive:
The important boundary here is axios' documented/read-side prototype-pollution hardening. The project threat model discusses polluted
Object.prototypefrom transitive dependencies as an in-scope read-side gadget class where axios should avoid picking up inherited behavior-changing properties. This issue is a bypass of that hardening at the Node HTTP request-options boundary.Technical details
The HTTP adapter constructs a null-prototype request options object before calling the selected transport:
That prevents direct inherited reads while the options object remains null-prototype. However, Node's HTTP client path copies or normalizes request options into ordinary objects before connection creation. After that copy, missing properties can resolve from
Object.prototypeagain.createConnectionis a sensitive Node HTTP option. If it is inherited after this copy, Node calls the attacker-supplied function to create the socket.Reproduction
The following minimal proof uses a legitimate target server and an attacker server. It pollutes
Object.prototype.createConnection, then makes an axios request to the legitimate server with an Authorization header.Observed result on the current npm package:
{ "response": "ATTACKER", "legitHits": [], "attackerHits": [ { "url": "/secret", "auth": "Bearer SECRET" } ] }The request never reached the intended target. The attacker-controlled server received the Authorization header and supplied the response body returned by axios.
Versions tested
I reproduced this against:
v1.xsource at commita8e4f13aeecc45a3b8fab3ecfd9ddb5d70fb772bFix validation
Adding an own safe value for
createConnectionto the adapter options object prevents inherited pollution from being observed after Node's option copy:With that guard in place, the same proof no longer calls the polluted function. The legitimate server receives the request, the attacker server receives nothing, and axios returns the legitimate response.
Remediation
Set own safe defaults for sensitive Node HTTP request options before calling
transport.request, at minimum:createConnection: undefinedI recommend reviewing other sensitive Node HTTP options that may be read after Node copies the request options into a normal object, especially connection/TLS-affecting fields such as
lookup,timeout,localAddress,servername,signal, and related options.Severity
CVSS:4.0/AV:N/AC:L/AT:P/PR:L/UI:N/VC:H/VI:H/VA:N/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: CIDR-form NO_PROXY entries are ignored, causing proxy exclusion bypass for internal IP ranges
CVE-2026-101899 / GHSA-44g4-m2mj-wpvx
More information
Details
Summary
Axios supports proxy environment variables and evaluates
NO_PROXYexclusions in the Node.js adapter. CIDR-formNO_PROXYentries such as127.0.0.0/8,10.0.0.0/8, or169.254.169.254/32are not interpreted as IP ranges. As a result, a request to an IP address inside a configured CIDR exclusion can still be sent through the configured proxy.This affects deployments that rely on CIDR notation to keep loopback, private, Kubernetes, CI, or cloud metadata traffic away from proxy infrastructure.
Impact
If the configured proxy is outside the intended trust boundary, requests that operators expected to bypass the proxy may be exposed to it. For plaintext HTTP targets, the proxy can see and modify URLs, headers, and bodies. For HTTPS targets, the proxy still observes connection metadata and may receive CONNECT requests that policy expected to avoid.
This is a proxy exclusion bypass, not arbitrary proxy injection by itself.
Affected Functionality
Affected:
HTTP_PROXY,HTTPS_PROXY,NO_PROXY, or lowercase equivalents.NO_PROXY.Not affected:
NO_PROXYentries where axios matching succeeds.proxy: false.Technical Details
lib/helpers/shouldBypassProxy.jsparses eachNO_PROXYentry into a host and optional port, normalizes hostnames, and then compares exact hostnames, suffix entries, wildcard-prefix entries, and loopback equivalents. It does not parse CIDR notation.Local verification on axios
1.18.1:The expected result for CIDR-aware bypass policy is
true.Proof of Concept of Attack
Constrained local demonstration:
HTTP_PROXY=http://127.0.0.1:<proxy-port>.NO_PROXY=127.0.0.0/8.http://127.0.0.1:<internal-port>/metadata.