GitHub Advisoryadvisory · npm
GHSA-42h9-826w-cgv3 Axios: Excessive recursion in formDataToJSON can cause denial of service
MEDIUM
Official page ↗
- Aliases
- CVE-2026-67313
- Ecosystem
- npm
- Packages
- axios
- Severity
- Moderate
- CVSS vector
- CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:N/VI:N/VA:L/SC:N/SI:N/SA:N
- Weaknesses
- CWE-400, CWE-674
- Reviewed
- 2026-07-20
Affected packages
• npm axios: >= 0.28.0, < 0.33.0 → fixed in 0.33.0
• npm axios: >= 1.0.0, < 1.18.0 → fixed in 1.18.0
Description
Summary
Axios versions `0.28.0` and later contain uncontrolled recursion in `formDataToJSON`, the helper behind the public `axios.formToJSON()` / named `formToJSON` API and the default request transform used when FormData is sent with an `application/json` content type.
Applications are affected when they pass attacker-controlled `FormData` field names into this functionality. A field name with thousands of nested bracket segments can exhaust the JavaScript call stack and throw `RangeError: Maximum call stack size exceeded`, causing request failure and, in applications that do not handle the exception or rejected promise, possible process termination.
Impact
The impact is denial of service against applications that process untrusted `FormData` field names through axios' FormData-to-JSON conversion.
The vulnerable path is not reached by merely installing axios, by normal multipart `FormData` pass-through, or by ordinary axios requests that do not request JSON serialisation of `FormData`. In the default axios request, the error is produced before network I/O and returned as a rejected Promise. Direct use of `formToJSON()` throws synchronously.
Server-side applications are the primary risk when remote users can submit arbitrary form field names, and the application converts those fields with `formToJSON()` or sends them through axios as JSON.
Affected Functionality
Affected APIs and paths:
• `axios.formToJSON(formData)`
• `import { formToJSON } from "axios"`
• `lib/helpers/formDataToJSON.js`
• axios default `transformRequest` when `data` is `FormData` and `Content-Type` contains `application/json`
Unaffected or lower-risk paths:
• Normal multipart `FormData` requests without `JSON Content-Type`
• `toFormData()` object-to-FormData serialisation, which already has a `maxDepth` guard
• Axios versions before 0.28.0, where this helper and public API were not present
Technical Details
`lib/helpers/formDataToJSON.js` parses a form field name into path segments with `parsePropPath()`. For a key such as `a[x][x][x]`, each bracketed segment becomes another path element.
`formDataToJSON()` then calls the nested `buildPath(path, value, target, index)` function. `buildPath()` recursively calls itself once for each path segment and does not enforce a maximum depth:
`const result = buildPath(path, value, target[name], index);`
A key containing thousands of bracket segments, therefore, creates thousands of recursive calls. At sufficient depth, V8 throws `RangeError: Maximum call stack size exceeded`.
Axios already applies a depth guard to the inverse serializer in `lib/helpers/toFormData.js`, where `maxDepth` defaults to 100 and exceeding it throws `AxiosError` with code `ERR_FORM_DATA_DEPTH_EXCEEDED`. `formDataToJSON()` does not currently have equivalent protection.
Proof of Concept of Attack
```js
import { formToJSON } from "axios";
const fd = new FormData();
fd.append("a" + "[x]".repeat(15000), "value");
try {
formToJSON(fd);
console.log("not vulnerable");
} catch (err) {
console.log(`${err.constructor.name}: ${err.message}`);
}
```
Expected vulnerable result:
RangeError: Maximum call stack size exceeded
The axios request transform path can also be reached before network I/O:
```js
import axios from "axios";
const fd = new FormData();
fd.append("a" + "[x]".repeat(15000), "value");
await axios
.post("http://127.0.0.1:1/", fd, {
headers: { "Content-Type": "application/json" }
})
.catch((err) => console.log(`${err.constructor.name}: ${err.message}`));
```
Expected vulnerable result:
RangeError: Maximum call stack size exceeded
Workarounds
Applications can avoid the vulnerable path by not converting attacker-controlled `FormData` to JSON with axios.
If conversion is required before a fixed axios release is available, validate `FormData` field names before calling `formToJSON()` or before sending `FormData` with `Content-Type: application/json`. Reject keys whose parsed nesting depth exceeds the application's expected schema.
For axios requests carrying untrusted `FormData`, avoid setting `Content-Type: application/json`; leaving the data as multipart FormData bypasses `formDataToJSON()`.
Catching the resulting error can prevent process termination, but it does not remove the uncontrolled-recursion behaviour and should not be treated as the primary mitigation.
Original Report
Axios SSRF via Incomplete Loopback Detection
CWE-918 | CVSS 7.5 (HIGH) | CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:L
---
1. Classification
| CWE | CVSS Score | Severity | Type |
|-----|-----------|----------|------|
| CWE-918 | 7.5 (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:L) | HIGH | Server-Side Request Forgery |
2. Description
Summary
The `shouldBypassProxy()` function in Axios fails to recognise `0.0.0.0`, `::`, and `::ffff:0.0.0.0` as loopback addresses. When `NO_PROXY=localhost` is configured, requests to these addresses are incorrectly forwarded through the proxy instead of being sent directly, enabling an SSRF attack against internal services reachable via the proxy's loopback interface.
Root Cause
File: `lib/helpers/shouldBypassProxy.js`
`isIPv4Loopback` (lines 3-8): Only checks for `127.x.x.x` addresses by inspecting `parts[0] !== '127'`. The `0.0.0.0` address has `parts[0] === '0'`, so it falls through as non-loopback, even though on Linux `0.0.0.0` routes to the loopback interface.
`isIPv6Loopback` (lines 10-38): Only checks `host === '::1'`. The `::` address (unspecified IPv6) also routes to the loopback, but is not recognised.
Attack Flow:
```
isIPv4Loopback (line 3) — fails for 0.0.0.0
→ isLoopback (line 44) — wraps both checks, returns false
→ shouldBypassProxy (line 127) — PUBLIC API, exported default
→ lib/adapters/http.js (line 190) — Node.js HTTP adapter
```
Attack Vector
• Access Vector: Network (AV:N)
• Access Complexity: Low (AC:L) — attacker only needs control of a URL
• Privileges Required: None (PR:N)
• User Interaction: None (UI:N)
3. Proof of Concept
Phase 1: Logic Verification
```javascript
import shouldBypassProxy from 'axios/lib/helpers/shouldBypassProxy.js';
// Normal loopback — correctly returns true (bypasses proxy)
shouldBypassProxy('http://127.0.0.1:9999/'); // → true
// Vulnerable — returns false (goes through proxy!)
shouldBypassProxy('http://0.0.0.0:9999/'); // → false ← SSRF
shouldBypassProxy('http://[::]:9999/'); // → false ← SSRF
shouldBypassProxy('http://[::ffff:0.0.0.0]:9999/'); // → false ← SSRF
```
Phase 2: Docker E2E Reproduction
A full 3-container Docker reproduction was created and tested:
• Proxy container: Simple HTTP forward proxy on port 8888
• Internal container: Internal service on port 9999 (simulates sensitive internal resource)
• Attacker container: Runs the test script with Axios source mounted
Reproduction steps:
```bash
cd /tmp/deep-e2e
docker compose up -d
docker compose exec attacker node test-ssrf.js
```
Results:
• Test 1: `127.0.0.1 + NO_PROXY=localhost` → BYPASS (correct)
• Test 2: `0.0.0.0 + NO_PROXY=localhost` → VIA_PROXY (SSRF)
• Test 3: `[::] + NO_PROXY=localhost` → VIA_PROXY (SSRF)
• Test 4: `[::ffff:0.0.0.0] + NO_PROXY=localhost` → VIA_PROXY (SSRF)
Phase 3: Actual Axios Client
The real Axios HTTP client (v1.16.1, source tree) was tested through proxy configuration:
• Axios with `proxy: { host: 'proxy', port: 8888 }`
• Setting `NO_PROXY=localhost` and requesting `http://0.0.0.0:9999/`
• Result: Axios forwarded the request through the proxy instead of bypassing it
4. Impact
Attack Scenario
1. Attacker has control over a URL that an Axios client will request (direct input, redirect target, open redirect chain)
2. The Axios client is configured with a proxy (e.g., corporate proxy) and `NO_PROXY=localhost` to protect internal services
3. Attacker supplies `http://0.0.0.0:8080/admin` as the target URL
4. Axios sends the request through the proxy
5. The pro…
Related
Alias · CVE (1)
- CVE-2026-67313 axios versions 0.28.0 and later contain uncontrolled recursion in formDataToJSON when processing FormData field names with deeply nested… vulnerability
References
- https://github.com/axios/axios/security/advisories/GHSA-42h9-826w-cgv3 web
- https://nvd.nist.gov/vuln/detail/CVE-2026-67313 advisory
- https://nvd.nist.gov/vuln/detail/CVE-2026-68942 advisory
- https://github.com/axios/axios/pull/11000 web
- https://github.com/axios/axios/pull/11001 web
- https://github.com/axios/axios/commit/1417285c69344bbcc6420a021f67dee0c6fedb2d web
- https://github.com/axios/axios/commit/32fc489632377d214db55bfa4e2c48486a7d7ce2 web
- https://github.com/axios/axios package
- https://github.com/axios/axios/releases/tag/v0.33.0 web
- https://github.com/axios/axios/releases/tag/v1.18.0 web
- https://www.vulncheck.com/advisories/axios-before-denial-of-service-via-formdatatojson web