[renovate] Update dependency axios to v1.15.2 [SECURITY]#679
[renovate] Update dependency axios to v1.15.2 [SECURITY]#679renovate[bot] wants to merge 1 commit intomainfrom
Conversation
✅ Deploy Preview for echoes-react ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
|
Renovate Jira issue ID: ECHOES-1302 |
Summary
Minimal dependency bump: axios updated from 1.15.0 → 1.15.2 to patch CVE-2026-42037, a CRLF injection vulnerability in multipart form-data handling (lib/helpers/formDataToStream.js). The vulnerability allows attackers to inject arbitrary headers in multipart parts via unsanitized blob.type values. Changes are limited to package.json and yarn.lock (version and checksum updates). Patch-level version bump indicates backward compatibility. What reviewers should knowFor reviewers:
|
There was a problem hiding this comment.
LGTM! ✅
Clean, minimal security patch — no issues found.
The Yarn resolutions override correctly redirects all axios instances in the dependency tree to 1.15.2, including sonarqube-scanner's transitive axios@1.13.6 dependency. The lockfile has a single axios entry (no stale 1.15.0 leftovers), and the checksum format is consistent with other Yarn Berry entries. axios is not imported anywhere in src/, so this codebase is not directly exposed to the CRLF injection vulnerability via its own code — but the transitive fix is still the right call.
|





This PR contains the following updates:
1.15.0→1.15.2Axios: 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)Step 4 — Execute the PoC
3.2 Observed Output
The following output was captured during testing on Kali Linux with Axios 1.15.0:
3.3 Analysis of Results
The output conclusively demonstrates the following:
Patched cases behave correctly: Requests to
localhost,localhost.(trailing dot), and[::1](bracketed IPv6) all result in a direct connection, confirming that the existing patch in Axios 1.15.0 correctly handles the cases reported in GHSA-3p68-rc4w-qgx5.Bypass cases confirm the incomplete patch: Requests to
127.0.0.2,127.0.0.100, and127.1.2.3all of which are valid loopback addresses within the127.0.0.0/8subnet as defined byRFC 1122 §3.2.1.3are transparently forwarded to the attacker-controlled proxy server. The proxy receives the full request including the HTTP method, target URL, andHostheader, demonstrating that any response from an internal service bound to these addresses would be fully intercepted.This confirms that the
NO_PROXYprotection configured by the developer (localhost,127.0.0.1,::1) fails silently for the entire127.0.0.0/8address range beyond127.0.0.1, providing a reproducible and reliable bypass of the security control introduced by the patch.4. Impact Assessment
This vulnerability is a security control bypass specifically an incomplete patch that allows an attacker to circumvent the
NO_PROXYprotection mechanism in Axios by using any loopback addresses within the127.0.0.0/8subnet other than127.0.0.1. The result is that traffic intended to remain private and direct is silently intercepted by a configured proxy server.4.1 Who Is Impacted?
Primary Target — Node.js Backend Applications
Any Node.js application that meets all three of the following conditions is vulnerable:
Affected Deployment Environments
Scale of Exposure
Axios is one of the most widely used HTTP client libraries in the JavaScript ecosystem, with over 500 million weekly downloads on npm. Any application in the above categories using Axios 1.15.0 is affected, regardless of whether the developer is aware of the underlying proxy routing logic.
4.3 Impact Details
Impact 1 Silent Interception of Internal Service Traffic
When an application makes a request to an internal loopback service using a non-standard loopback address (e.g.,
http://127.0.0.2/admin), Axios silently routes the request through the configured proxy instead of connecting directly.The developer receives no error or warning. From the application's perspective, the request succeeds normally.
Impact 2 — SSRF Mitigation Bypass
Many applications implement SSRF protections by configuring
NO_PROXYto prevent requests to loopback addresses from being forwarded externally. This bypass defeats that protection entirely for any loopback address beyond127.0.0.1.An attacker who can influence the target URL of an Axios request through user-supplied input, redirect chains, or other SSRF vectors can exploit this gap to reach internal services that the developer explicitly intended to protect.
Impact 3 — Cloud Metadata Service Exposure
In cloud environments (AWS, GCP, Azure), SSRF vulnerabilities are particularly severe because they can be used to access the instance metadata service and retrieve IAM credentials, enabling full cloud account compromise.
While the AWS IMDSv2 service is reachable at
169.254.169.254(not a loopback address), many cloud deployments run internal metadata proxies, credential servers, or service discovery endpoints bound to non-standard loopback addresses within the127.0.0.0/8range. An attacker reaching any of these services through the bypass could:Impact 4 — Confidential Data Exfiltration
Any internal service binding to a
127.x.x.xaddress other than127.0.0.1is fully exposed. This includes:Impact 5 — No Indication of Compromise
A particularly dangerous characteristic of this vulnerability is that it is completely silent neither the application nor the developer receives any indication that requests are being routed incorrectly. There are no error messages, no exceptions thrown, and no changes in application behaviour. The proxy interception is entirely transparent from the application's perspective, making detection extremely difficult without active network monitoring.
4.4 Comparison with Original Vulnerability
The severity of this finding is equivalent to the original vulnerability because the attack conditions, exploitation technique, and resulting impact are identical. The only difference is the specific input used to trigger the bypass, which the existing patch completely fails to address.
5. Technical Remediation & Proposed Fix
5.1 Vulnerable Code Block
The vulnerability resides in
lib/helpers/shouldBypassProxy.jsat lines 1–3. The following is the exact code extracted from Axios 1.15.0:This hardcoded
Setis subsequently used at line 108 during the final NO_PROXY match evaluation: