# Axios: Prototype Pollution Gadget in axios toFormData Options

Axios toFormData reads visitor/maxDepth/dots/indexes/metaTokens/Blob without own-property guards, so pre-existing Object.prototype pollution hijacks form serialization, leaking field values or causing DoS.

- Payout: Research
- Severity: high
- Program: Axios
- Found by: chan154
- Disclosed: 2026-09-30
- CVE: CVE-2026-101909
- Write-up quality: 7/10
- Original: https://github.com/advisories/GHSA-x97p-jq2g-jp4f
- Library page: https://bugbountylibrary.com/r/ghsa%3AGHSA-x97p-jq2g-jp4f
- Tags: area:oss domain:oss impact:data-leak impact:dos impact:integrity kind:research platform:ghsa sev:high tech:nodejs technique:chained technique:source-review vuln:prototype-pollution

**Target:** npm library form serializer (lib/helpers/toFormData.js)
**Root cause:** toFlatObject returns the plain default options object unchanged when options is undefined, and toFormData then reads six behavior-affecting properties directly without hasOwnProp guards, resolving inherited polluted values from Object.prototype.
**Steps:**
1. `npm install axios@1.18.1` in a fresh project
2. Pollute the prototype: `Object.prototype.visitor = function(value, key, path, helpers){ stolen.push({key, value}); return helpers.defaultVisitor.call(this, value, key, path); }` and `Object.prototype.maxDepth = 2`
3. POST a plain object with `Content-Type: multipart/form-data` via `axios.post(url, {username:'john', password:'SuperSecret123!', profile:{ssn:'123-45-6789'}})`
4. Observe the polluted visitor invoked per field, capturing values including nested `ssn`
5. POST `{ a: { b: { c: { d: 'value' } } } }` to trigger `ERR_FORM_DATA_DEPTH_EXCEEDED` from polluted maxDepth
**How found:** Researcher noted axios's prototype pollution defenses (mergeConfig returning Object.create(null), own() helper) only cover the config object; audited toFormData's internal options object, found toFlatObject's early return for undefined source hands back a plain object literal inheriting Object.prototype, then traced six unguarded property reads.
**Exploitation:** Requires a separate same-process prototype pollution primitive (e.g. compromised transitive dependency). Attacker sets Object.prototype.visitor to a function that records value/key/path then delegates to helpers.defaultVisitor, so requests succeed normally while secrets (passwords, tokens, PII) are silently exfiltrated; polluted maxDepth/dots/indexes/metaTokens alternatively cause DoS or silent field-name corruption.
**Escalation:** Polluted visitor yields transparent interception of all serialized form fields; maxDepth pollution scales to service-level DoS across nested-form workflows.
**Insight:** Prototype-pollution hardening scoped to the config/merge boundary leaves internal helper-created option objects exposed; audit every plain-object default that flows into a serializer for inherited-property reads, especially callback-valued options like visitor.

