chore(deps): update dependency axios@<1.13.5 to v1.15.2 [security]#2572
Open
renovate[bot] wants to merge 1 commit intomainfrom
Open
chore(deps): update dependency axios@<1.13.5 to v1.15.2 [security]#2572renovate[bot] wants to merge 1 commit intomainfrom
renovate[bot] wants to merge 1 commit intomainfrom
Conversation
2127bf6 to
9488fbe
Compare
9488fbe to
3fc9374
Compare
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.13.5→1.15.2Axios has a NO_PROXY Hostname Normalization Bypass that Leads to SSRF
CVE-2025-62718 / GHSA-3p68-rc4w-qgx5
More information
Details
Axios does not correctly handle hostname normalization when checking
NO_PROXYrules.Requests to loopback addresses like
localhost.(with a trailing dot) or[::1](IPv6 literal) skipNO_PROXYmatching and go through the configured proxy.This goes against what developers expect and lets attackers force requests through a proxy, even if
NO_PROXYis set up to protect loopback or internal services.According to RFC 1034 §3.1 and RFC 3986 §3.2.2, a hostname can have a trailing dot to show it is a fully qualified domain name (FQDN). At the DNS level,
localhost.is the same aslocalhost.However, Axios does a literal string comparison instead of normalizing hostnames before checking
NO_PROXY. This causes requests likehttp://localhost.:8080/andhttp://[::1]:8080/to be incorrectly proxied.This issue leads to the possibility of proxy bypass and SSRF vulnerabilities allowing attackers to reach sensitive loopback or internal services despite the configured protections.
PoC
Expected: Requests bypass the proxy (direct to loopback).
Actual: Proxy logs requests for
localhost.and[::1].Impact
Applications that rely on
NO_PROXY=localhost,127.0.0.1,::1for protecting loopback/internal access are vulnerable.Attackers controlling request URLs can:
Affected Versions
NO_PROXYevaluation.Remediation
Axios should normalize hostnames before evaluating
NO_PROXY, including:Severity
CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:L/VI:L/VA:N/SC:L/SI:L/SA:NReferences
This data is provided by OSV and the GitHub Advisory Database (CC-BY 4.0).
Axios has Unrestricted Cloud Metadata Exfiltration via Header Injection Chain
CVE-2026-40175 / GHSA-fvcv-3m26-pcqx
More information
Details
Vulnerability Disclosure: Unrestricted Cloud Metadata Exfiltration via Header Injection Chain
Summary
The Axios library is vulnerable to a specific "Gadget" attack chain that allows Prototype Pollution in any third-party dependency to be escalated into Remote Code Execution (RCE) or Full Cloud Compromise (via AWS IMDSv2 bypass).
While Axios patches exist for preventing check pollution, the library remains vulnerable to being used as a gadget when pollution occurs elsewhere. This is due to a lack of HTTP Header Sanitization (CWE-113) combined with default SSRF capabilities.
Severity: Critical (CVSS 9.9)
Affected Versions: All versions (v0.x - v1.x)
Vulnerable Component:
lib/adapters/http.js(Header Processing)Usage of "Helper" Vulnerabilities
This vulnerability is unique because it requires Zero Direct User Input.
If an attacker can pollute
Object.prototypevia any other library in the stack (e.g.,qs,minimist,ini,body-parser), Axios will automatically pick up the polluted properties during its config merge.Because Axios does not sanitise these merged header values for CRLF (
\r\n) characters, the polluted property becomes a Request Smuggling payload.Proof of Concept
1. The Setup (Simulated Pollution)
Imagine a scenario where a known vulnerability exists in a query parser. The attacker sends a payload that sets:
2. The Gadget Trigger (Safe Code)
The application makes a completely safe, hardcoded request:
3. The Execution
Axios merges the prototype property
x-amz-targetinto the request headers. It then writes the header value directly to the socket without validation.Resulting HTTP traffic:
4. The Impact (IMDSv2 Bypass)
The "Smuggled" second request is a valid
PUTrequest to the AWS Metadata Service. It includes the requiredX-aws-ec2-metadata-token-ttl-secondsheader (which a normal SSRF cannot send).The Metadata Service returns a session token, allowing the attacker to steal IAM credentials and compromise the cloud account.
Impact Analysis
Cookie,Authorization) to pivot into internal administrative panels.Hostheaders to poison shared caches.Recommended Fix
Validate all header values in
lib/adapters/http.jsandxhr.jsbefore passing them to the underlying request function.Patch Suggestion:
References
This report was generated as part of a security audit of the Axios library.
Severity
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:NReferences
This data is provided by OSV and the GitHub Advisory Database (CC-BY 4.0).
Axios: CRLF Injection in multipart/form-data body via unsanitized blob.type in formDataToStream
CVE-2026-42037 / GHSA-445q-vr5w-6q77
More information
Details
Summary
The
FormDataPartconstructor inlib/helpers/formDataToStream.jsinterpolatesvalue.typedirectly into theContent-Typeheader of each multipart part without sanitizing CRLF (\r\n) sequences. An attacker who controls the.typeproperty of a Blob/File-like object (e.g., via a user-uploaded file in a Node.js proxy service) can inject arbitrary MIME part headers into the multipart form-data body. This bypasses Node.js v18+ built-in header protections because the injection targets the multipart body structure, not HTTP request headers.Details
In
lib/helpers/formDataToStream.jsat line 27, when processing a Blob/File-like value, the code builds per-part headers by directly embedding value.type:Note that the string path (line above) explicitly sanitizes CRLF, but the binary/blob path does not. This inconsistency confirms the sanitization was intended but missed for
value.type.Attack chain:
\r\nsequencesaxios.post(url, formData)formDataToStream(), which passesvalue.typeunsanitized into the multipart bodyThis is reachable via the fully public axios API (
axios.post(url, formData)) with no special configuration.Additionally,
value.nameused in theContent-Dispositionconstruction nearby likely has the same issue and should be audited.PoC
Prerequisites: Node.js 18+, axios (tested on 1.14.0)
Steps to reproduce:
Expected behavior: value.type should be sanitized to strip \r\n before interpolation, consistent with the string value path.
Actual behavior: CRLF sequences in value.type are preserved, allowing arbitrary header injection in multipart parts.
Impact
Any Node.js application that accepts user-provided files (with attacker-controlled MIME types) and re-posts them via axios FormData is affected. This is a common pattern in proxy services, file upload relays, and API gateways.
Consequences include: bypassing server-side Content-Type-based upload filters, confusing multipart parsers into misrouting data, injecting phantom form fields if the boundary is known, and exploiting downstream server vulnerabilities that trust per-part headers.
axios is one of the most downloaded npm packages, significantly increasing the blast radius of this issue.
Suggested fix
In formDataToStream.js, sanitize value.type before interpolating it into the per-part Content-Type header. Apply the same strategy used for string values (strip/replace \r\n) or use the same escapeName logic.
Severity
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:NReferences
This data is provided by OSV and the GitHub Advisory Database (CC-BY 4.0).
Axios' HTTP adapter-streamed uploads bypass maxBodyLength when maxRedirects: 0
CVE-2026-42034 / GHSA-5c9x-8gcm-mpgx
More information
Details
Summary
For stream request bodies, maxBodyLength is bypassed when maxRedirects is set to 0 (native http/https transport path). Oversized streamed uploads are sent fully even when the caller sets strict body limits.
Details
Relevant flow in lib/adapters/http.js:
This creates a path-specific bypass for streamed uploads.
PoC
Environment:
Steps:
Observed:
Control checks:
Impact
Type: DoS / uncontrolled upstream upload / resource exhaustion.
Impacted: Node.js services using streamed request bodies with maxBodyLength expecting hard enforcement, especially when following Axios guidance to use maxRedirects: 0 for streams.
Severity
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:LReferences
This data is provided by OSV and the GitHub Advisory Database (CC-BY 4.0).
Axios: unbounded recursion in toFormData causes DoS via deeply nested request data
CVE-2026-42039 / GHSA-62hf-57xw-28j9
More information
Details
Summary
toFormData recursively walks nested objects with no depth limit, so a deeply nested value passed as request data crashes the Node.js process with a RangeError.
Details
lib/helpers/toFormData.js:210 defines an inner
build(value, path)that recurses into every object/array child (line 225:build(el, path ? path.concat(key) : [key])). The only safeguard is astackarray used to detect circular references; there is no maximum depth and no try/catch around the recursion. Becausebuildcalls itself once per nesting level, a payload nested roughly 2000+ levels deep exhausts V8's call stack.toFormDatais the serializer behindFormDatarequest bodies andAxiosURLSearchParams(used bybuildURLwhenparamsis an object withURLSearchParamsunavailable, seelib/helpers/buildURL.js:53andlib/helpers/AxiosURLSearchParams.js:36). Any server-side code that forwards a client-supplied object intoaxios({ data, params })therefore reaches the recursive walker with attacker-controlled depth.The RangeError is thrown synchronously from inside
forEach, escapestoFormData, and propagates out of the axios request call. In typical Express/Fastify request handlers this terminates the running request; in synchronous startup paths or worker threads it can crash the whole process.PoC
Server-side reachability example:
Verified on axios 1.15.0 (latest, 2026-04-10), Node.js 20, 3/3 PoC runs reproduce the RangeError at depth 2500.
Impact
A remote, unauthenticated attacker who can influence an object passed to axios as request
dataorparamstriggers an uncaught RangeError inside the synchronous recursive walker. In server-side applications that proxy or re-send client JSON through axios this crashes the request handler and, in worker/cluster setups, the process. Fix by bounding recursion depth intoFormData'sbuildfunction (reject or throw on depths beyond a configurable limit, e.g. 100) or rewriting the walker iteratively.Severity
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:L/SC:N/SI:N/SA:NReferences
This data is provided by OSV and the GitHub Advisory Database (CC-BY 4.0).
Axios: Header Injection via Prototype Pollution
CVE-2026-42035 / GHSA-6chq-wfr3-2hj9
More information
Details
Summary
A prototype pollution gadget exists in the Axios HTTP adapter (lib/adapters/http.js) that allows an attacker to inject arbitrary HTTP headers into outgoing requests. The vulnerability exploits duck-type checking of the data payload, where if Object.prototype is polluted with getHeaders, append, pipe, on, once, and Symbol.toStringTag, Axios misidentifies any plain object payload as a FormData instance and calls the attacker-controlled getHeaders() function, merging the returned headers into the outgoing request.
The vulnerable code resides exclusively in lib/adapters/http.js. The prototype pollution source does not need to originate from Axios itself — any prototype pollution primitive in any dependency in the application's dependency tree is sufficient to trigger this gadget.
Prerequisites:
A prototype pollution primitive must exist somewhere in the application's dependency chain (e.g., via lodash.merge, qs, JSON5, or any deep-merge utility processing attacker-controlled input). The pollution source is not required to be in Axios.
The application must use Axios to make HTTP requests with a data payload (POST, PUT, PATCH).
Details
The vulnerability is in
lib/adapters/http.js, in the data serialization pipeline:Axios uses two sequential duck-type checks, both of which can be satisfied via prototype pollution:
1.
utils.isFormData(data)—lib/utils.js2.
utils.isFunction(data.getHeaders)— Duck-type forform-datanpm packagePoC
Impact
Note on Scope: There is an argument to promote this from S:U to S:C (Scope: Changed), which would raise the score to 10.0. In some architectures, Axios is commonly used for service to service communication where downstream services trust identity headers (
Authorization,X-Role,X-User-ID,X-Tenant-ID) forwarded from upstream API gateways. In this scenario, the vulnerable component (Axios in Service A) and the impacted component (Service B, which acts on the injected identity) are under different security authorities. The injected headers cross a trust boundary, meaning the impact extends beyond the security scope of the vulnerable component, the CVSS v3.1 definition of a Scope Change. We conservatively score S:U here, but maintainers should evaluate which one applies better here.Recommended Fix
Add an explicit own-property check in
lib/adapters/http.js:Severity
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:NReferences
This data is provided by OSV and the GitHub Advisory Database (CC-BY 4.0).
Axios: no_proxy bypass via IP alias allows SSRF
CVE-2026-42038 / GHSA-m7pr-hjqh-92cm
More information
Details
The fix for no_proxy hostname normalization bypass (#10661) is incomplete.When no_proxy=localhost is set, requests to 127.0.0.1 and [::1] still route through the proxy instead of bypassing it.
The shouldBypassProxy() function does pure string matching — it does not
resolve IP aliases or loopback equivalents. As a result:
POC :
process.env.no_proxy = 'localhost';
process.env.http_proxy = 'http://attacker-proxy:8888';
Inside
mergeConfig, the merged config is built as a plain{}object (lib/core/mergeConfig.js#L20):A plain
{}inherits fromObject.prototype.mergeConfigonly iteratesObject.keys({ ...config1, ...config2 })(line 99), which is a spread of own properties. Any key that is absent from boththis.defaultsand the per-request config will never be set as an own property on the merged config. Reading that key later on the merged config falls through toObject.prototype. That is the root mechanism behind all gadgets below.Gadget 1: parseReviver -- response tampering and exfiltration
Introduced in: v1.12.0 (commit 2a97634, PR #5926)
Affected range: >= 1.12.0, <= 1.13.6
Root cause
The default
transformResponsefunction callsJSON.parse(data, this.parseReviver):thisis the merged config.parseReviveris not present indefaultsand is not in themergeMapinsidemergeConfig. It is never set as an own property on the merged config. Accessingthis.parseRevivertherefore walks the prototype chain.The call fires by default on every string response body because
lib/defaults/transitional.js#L5sets:which activates the JSON parse path unconditionally when
responseTypeis unset.JSON.parse(text, reviver)calls the reviver for every key-value pair in the parsed result, bottom-up. The reviver's return value is what the caller receives. An attacker-controlled reviver can both observe every key-value pair and silently replace values.There is no interaction with
assertOptionshere. TheassertOptionscall inAxios._request(line 119) iteratesObject.keys(config), and sinceparseReviverwas never set as an own property, it is not in that list. Nothing validates or invokes the polluted function beforetransformResponsedoes.Verification: own-property check
Proof of concept
Two terminals. The server simulates a legitimate API endpoint. The client simulates a Node.js application whose process has been affected by prototype pollution from a co-dependency.
Terminal 1 -- server (
server_gadget1.mjs):Terminal 2 -- client (
poc_parsereviver.mjs):The server sent
role: user. The application receivedrole: admin. The response is silently modified in place; no error is thrown, no log entry is produced.Gadget 2: transport -- full HTTP request hijacking with credentials
Introduced in: early adapter refactor, present across 0.x and 1.x
Affected range: >= 0.19.0, <= 1.13.6 (Node.js http adapter only)
Root cause
Inside the Node.js http adapter at
lib/adapters/http.js#L676:transportis listed inmergeMapinsidemergeConfig(line 88):but it is not present in
lib/defaults/index.jsat all.mergeConfigiteratesObject.keys({ ...config1, ...config2 })(line 99). Sinceconfig1(the defaults) has notransportkey and a typical per-request config has none either, the key never enters the loop. It is never set as an own property on the merged config. The read at line 676 falls through toObject.prototype.The fix in v1.13.5 (PR #7369) added a
hasOwnPropcheck formergeMapaccess, but the iteration set itself is the issue --transportsimply never enters it. The fix does not address this.The transport interface is
{ request(options, handleResponseCallback) }. The options object passed totransport.requestat adapter runtime contains:options.hostname,options.port,options.path-- full target URLoptions.auth-- basic auth credentials in"username:password"form (set at line 606)options.headers-- all request headers as a plain objectProof of concept
Two terminals. The server is a legitimate API endpoint that processes the request normally. The client's process has been affected by prototype pollution.
Terminal 1 -- server (
server_gadget2.mjs):Terminal 2 -- client (
poc_transport.mjs):The basic auth credentials are fully visible to the attacker's transport function. The request completes normally from the caller's perspective.
Additional gadget: transformRequest / transformResponse
Separately,
mergeConfigreadsconfig2[prop]at line 102 without ahasOwnPropertyguard. For keys liketransformRequestandtransformResponsethat are present indefaults(and therefore processed by the mergeMap loop), ifObject.prototype.transformRequestis polluted before the request,config2["transformRequest"]inherits the polluted value anddefaultToConfig2replaces the safe default transforms with the attacker's function.This one requires a discriminator because
assertOptionsinAxios._request(line 119) readsschema[opt]for every key in the merged config's own keys, andschema["transformRequest"]also inherits fromObject.prototype, causing it to call the polluted value as a validator. The gadget function needs to returntruewhen its first argument is a function (the assertOptions call) and perform the attack when its first argument is data (thetransformDatacall).Both
transformRequest(fires with request body) andtransformResponse(fires with response body) are confirmed affected. Range: >= 0.19.0, <= 1.13.6.Why the existing fix does not cover these
PR #7369 / CVE-2026-25639 (fixed in v1.13.5) addressed a separate class: passing
{"__proto__": {"x": 1}}as the config object, which causedmergeMap['__proto__']to resolve toObject.prototype(a non-function), crashing axios. The fix added an explicit block on__proto__,constructor, andprototypeas config keys, and changedmergeMap[prop]toutils.hasOwnProp(mergeMap, prop) ? mergeMap[prop] : ....That fix only addresses config keys that are explicitly set to
__proto__(or similar) by the caller. It does not addhasOwnPropertyguards on the value reads (config2[prop]at line 102,this.parseReviver,config.transport). An application using a PP-vulnerable co-dependency and making axios requests is still fully exposed after upgrading to 1.13.5 or 1.13.6.Suggested fixes
For
parseReviver(lib/defaults/index.js#L124):For
mergeConfigvalue reads (lib/core/mergeConfig.js#L102):For
transportand other adapter reads from config (lib/adapters/http.js#L676):The same
hasOwnProppattern applies tolookup,httpVersion,http2Options,family, andformSerializerreads in the adapter.Environment
Disclosure
Reported via GitHub Security Advisories at https://github.com/axios/axios/security/advisories/new per the axios security policy.
Severity
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:NReferences
This data is provided by OSV and the GitHub Advisory Database (CC-BY 4.0).
Axios: Incomplete Fix for CVE-2025-62718 — NO_PROXY Protection Bypassed via RFC 1122 Loopback Subnet (127.0.0.0/8) in Axios 1.15.0
CVE-2026-42043 / GHSA-pmwg-cvhr-8vh7
More information
Details
1. Executive Summary
This report documents an incomplete security patch for the previously disclosed vulnerability GHSA-3p68-rc4w-qgx5 (CVE-2025-62718), which affects the
NO_PROXYhostname resolution logic in the Axios HTTP library.Background — The Original Vulnerability
The original vulnerability (GHSA-3p68-rc4w-qgx5) disclosed that Axios did not normalize hostnames before comparing them against
NO_PROXYrules. Specifically, a request tohttp://localhost./(with a trailing dot) orhttp://[::1]/(with IPv6 bracket notation) would bypass NO_PROXY matching entirely and be forwarded to the configured HTTP proxy — even whenNO_PROXY=localhost,127.0.0.1,::1was explicitly set by the developer to protect loopback services.The Axios maintainers addressed this in version 1.15.0 by introducing a
normalizeNoProxyHost()function inlib/helpers/shouldBypassProxy.js, which strips trailing dots from hostnames and removes brackets from IPv6 literals before performing the NO_PROXY comparison.The Incomplete Patch — This Finding
While the patch correctly addresses the specific cases reported (trailing dot normalization and IPv6 bracket removal), the fix is architecturally incomplete.
The patch introduced a hardcoded set of recognized loopback addresses:
However, RFC 1122 §3.2.1.3 explicitly defines the entire 127.0.0.0/8 subnet as the IPv4 loopback address block not just the single address
127.0.0.1. On all major operating systems (Linux, macOS, Windows with WSL), any IP address in the range127.0.0.2through127.255.255.254is a valid, functional loopback address that routes to the local machine.As a result, an attacker who can influence the target URL of an Axios request can substitute 127.0.0.1 with any other address in the
127.0.0.0/8range (e.g.,127.0.0.2,127.0.0.100,127.1.2.3) to completely bypass theNO_PROXYprotection even in the fully patched Axios 1.15.0 release.Verification
This bypass has been independently verified on:
The Proof-of-Concept demonstrates that while
localhost,localhost., and[::1]are correctly blocked by the patched version, requests to127.0.0.2,127.0.0.100, and127.1.2.3are transparently forwarded to the attacker-controlled proxy server, confirming that the patch does not cover the full RFC-defined loopback address space.2. Deep-Dive: Technical Root Cause Analysis
2.1 Vulnerable File & Location
2.2 How Axios Routes HTTP Requests The Call Chain
When Axios dispatches any HTTP request,
lib/adapters/http.jscallssetProxy(), which invokesshouldBypassProxy()to decide whether to honour a configured proxy:shouldBypassProxy()is the single gatekeeper for NO_PROXY enforcement. A bypass here means all proxy protection fails silently.2.3 The Original Vulnerability (GHSA-3p68-rc4w-qgx5)
Before Axios 1.15.0, hostnames were compared against
NO_PROXYusing a raw literal string match with no normalization:Both
localhost.(FQDN trailing dot, RFC 1034 §3.1) and[::1](bracketed IPv6 literal, RFC 3986 §3.2.2) are canonical representations of loopback addresses, but Axios treated them as unknown hosts.2.4 What the Patch Fixed (Axios 1.15.0)
The patch introduced three changes inside
lib/helpers/shouldBypassProxy.js:Fix A
normalizeNoProxyHost()(Lines 47–57)Strips alternate representations before comparison:
Fix B Cross-Loopback Equivalence (Lines 1–3 & 108)
Allows
127.0.0.1andlocalhostto match each other interchangeably:Fix C Normalization Applied on Both Sides (Lines 81 & 90)
2.5 The Incomplete Patch Exact Root Cause
The fundamental flaw resides in Line 1:
*RFC 1122 §3.2.1.3 is unambiguous:
This means all addresses from
127.0.0.1through127.255.255.254are valid loopback addresses on any RFC-compliant operating system. On Linux, the entire/8block is routed to thelointerface by default. The patch recognises only127.0.0.1, leaving16,777,213valid loopback addresses unprotected.2.6 Step-by-Step Bypass Execution Trace
Environment:
Annotated execution of shouldBypassProxy("http://127.0.0.2:9191/internal-api"):
2.7 Why the Patch Design Is Flawed
The patch addresses the symptom (two specific alternate representations) rather than the root cause (an incomplete definition of what constitutes a loopback address).
Real-world services that commonly bind to non-standard loopback addresses include:
3. Comprehensive Attack Vector & Proof of Concept
3.1 Reproduction Steps
Step 1 — Create a fresh project directory
Step 2 — Initialize the project with the patched Axios version
Create
package.json:Install dependencies:
Verify the installed version:
Step 3 — Create the PoC file (
poc.js)