VDB
Sign up
HIGH8.2

GHSA-xp7r-j8r6-j9h3

parse-nested-form-data has Prototype Pollution via `__proto__` in FormData field names

Quick fix

GHSA-xp7r-j8r6-j9h3 — parse-nested-form-data: upgrade to the fixed version with the command below.

npm install parse-nested-form-data@1.0.1

Details

## Summary

`parseFormData()` walks bracket and dot-notation FormData field names into nested objects without filtering reserved property keys. A single FormData field whose name begins with `__proto__`, or contains `.__proto__.` mid-path, causes the parser to traverse onto `Object.prototype` and assign properties there, polluting the prototype chain of every plain object in the running process.

## Details

The vulnerability is in `handlePathPart` in `src/index.ts`, which performs `currentObject[pathPart.path]` and `currentObject[pathPart.path] = val` for object-type path segments without rejecting reserved keys. When the segment is `__proto__`, the read returns `Object.prototype`, which then becomes the next traversal target, and the next assignment lands on the prototype.

Reproduction on a fresh install of `parse-nested-form-data@1.0.0`:

```js import { parseFormData } from 'parse-nested-form-data'; const fd = new FormData(); fd.append('__proto__.polluted', 'yes'); parseFormData(fd); console.log(({}).polluted); // -> 'yes' console.log(([]).polluted); // -> 'yes' ```

Equivalent vectors:

- `__proto__[polluted]=yes` - `a.__proto__.polluted=yes` (mid-path traversal) - `a[0].__proto__.polluted=yes` (mid-path through an array element)

`constructor.prototype.x` was incidentally blocked by an existing duplicate-key guard (because `Object` is a function and failed the JSON-object check), but relying on that was fragile, so the fix denylists `constructor` and `prototype` as well as `__proto__`. The array branch (`a[0]`, `a[]`) was not exploitable in practice - the regex restricts array-index segments to digit characters - but the forbidden-key check is applied before the object/array type branching as defense in depth, so any future change to the regex cannot reintroduce the issue.

## Impact

Any application that passes attacker-controlled `FormData` (or any `Iterable<[string, string | File]>`) to `parseFormData()` - typically an HTTP server processing form submissions - allows an unauthenticated remote client to mutate `Object.prototype` of the running process via a single field name. Concrete consequences depend on the host application and may include corrupted application state, altered control flow in code that reads ambient properties off objects, and denial of service.

## Patches

Fixed in **1.0.1**. `handlePathPart` now throws a new `ForbiddenKeyError` (also exported) when any path segment is `__proto__`, `constructor`, or `prototype`, regardless of whether the segment would be used as an object key or an array index. The check runs before object/array type branching for defense in depth.

Upgrade:

``` npm install parse-nested-form-data@^1.0.1 ```

## Workarounds

If upgrading is not possible, validate field names before calling `parseFormData()`:

```js const FORBIDDEN = /(^|\.)(__proto__|constructor|prototype)($|[.[])/; for (const [name] of formData.entries()) { if (FORBIDDEN.test(name)) throw new Error('Unsafe field name'); } ```

## Resources

- CWE-1321: Improperly Controlled Modification of Object Prototype Attributes ('Prototype Pollution') - Fix commit: 527ad58eb486e32438f7198fb88315c20449d792

Are you affected?

Enter the version of the package you're using.

Affected packages

npm/parse-nested-form-data
Introduced in: 0Fixed in: 1.0.1
Fixnpm install parse-nested-form-data@1.0.1

References