GHSA-jggr-w7fw-pc2j json
fast-copy: Stack exhaustion in fast-copy when copying deeply-nested values
published 2026-10-05 34 d ago modified 2026-10-05 34 d ago
- cvss
- —
- not scored
- cisa kev
- Not listed
- not in CISA's catalog
- epss
- —
- no score, EPSS covers CVEs only
- public exploits
- 0
- none known
Summary
## Summary
`fast-copy` traverses values recursively with no bound on depth. Copying a sufficiently deeply-nested value exhausts the JavaScript call stack and throws a native `RangeError: Maximum call stack size exceeded` from inside the library.
## Details
Both `copy` and `copyStrict` recurse once per level of nesting. The value does not need to be circular (circular references were already handled correctly via an internal cache) and it does not need to be large. A plain object nested a few thousand levels deep is only a few kilobytes of equivalent JSON.
Measured depths at which copying begins to fail (Node.js, V8; the exact ceiling varies with JIT state and the stack available to the environment):
| Call | Last depth that copies successfully | | -------------------- | ----------------------------------- | | `copy(object)` | 2811 | | `copy(array)` | 3983 | | `copyStrict(object)` | 1874 | | `copyStrict(array)` | 1874 |
`JSON.parse` is iterative and parses deeply-nested input without difficulty, so a payload that deserializes cleanly can fail in a subsequent `copy` call.
## Impact
The failure is a synchronous, catchable `RangeError` confined to the `copy` call that received the value. There are no memory safety concerns, no data exposure, and no effect on state outside that call. In a typical server the result is a failed request rather than a failed process.
Applications that call `copy` on externally-supplied data, such as request bodies, cached payloads, merged configuration, etc., do not expect a clone helper to throw may surface this as an unhandled error.
## Patches
Fixed in 4.1.0, and backported to 3.1.0 and 2.2.0 so that every major line has a patch available without requiring a breaking upgrade.
Traversal is now bounded by a `maxDepth` option, defaulting to `1000`, which sits below the native limit in standard environments. Exceeding it throws `MaxDepthExceededError`, which carries the limit that was exceeded and extends `RangeError` so existing handling continues to match.
The limit is configurable for consumers with legitimately deep data. On `3.x` and `4.x` it is set when creating a copier:
```js import { createCopier } from 'fast-copy';
export const copy = createCopier({ maxDepth: 5000 }); ```
On `2.x` it is passed per call, and the error is a property of the exported function rather than a named export:
```js import copy from 'fast-copy';
copy(value, { maxDepth: 5000 }); // detection: error instanceof copy.MaxDepthExceededError ```
In legacy environments without `Object.setPrototypeOf`, `instanceof MaxDepthExceededError` cannot be supported; check `error.name === 'MaxDepthExceededError'` or `error instanceof RangeError` instead.
Patch / fix
- npm fast-copy 2.2.0, 3.1.0, 4.1.0
- github.com/planttheidea/fast-copy@359c008 commit
- github.com/planttheidea/fast-copy@caa7caa commit
- github.com/planttheidea/fast-copy@dedf465 commit
- github.com/planttheidea/fast-copy#137 pull request
- github.com/planttheidea/fast-copy#138 pull request
- github.com/planttheidea/fast-copy#139 pull request
- github.com/planttheidea/fast-copy/releases/tag/v2.2.0 release
- github.com/planttheidea/fast-copy/releases/tag/v3.1.0 release
- github.com/planttheidea/fast-copy/releases/tag/v4.1.0 release
Affected packages
| ecosystem | package | affected | fixed in |
|---|---|---|---|
| npm | fast-copy | >=4.0.0, <4.1.0 >=3.0.0, <3.1.0 <2.2.0 |
4.1.0 3.1.0 2.2.0 |
Classification
- Weakness
-
- CWE-674 Uncontrolled Recursion
References
-
github.com
/planttheidea/fast-copy/pull/137
web
-
github.com
/planttheidea/fast-copy/pull/138
web
-
github.com
/planttheidea/fast-copy/pull/139
web
-
github.com
/planttheidea/fast-copy/commit/359c00884ae8ae31f10925fd0e2fc66661db6cef
web
-
github.com
/planttheidea/fast-copy/commit/caa7caace65767dfe252f0dc5115d82c99ca16b9
web
-
github.com
/planttheidea/fast-copy/commit/dedf465e5329fbd149f13b53521af962d16ff8df
web
-
github.com
/planttheidea/fast-copy/security/advisories/GHSA-jggr-w7fw-pc2j
web
-
github.com
/planttheidea/fast-copy
package
-
github.com
/planttheidea/fast-copy/releases/tag/v2.2.0
web
-
github.com
/planttheidea/fast-copy/releases/tag/v3.1.0
web
-
github.com
/planttheidea/fast-copy/releases/tag/v4.1.0
web
Sources
- GitHub Advisory GHSA-jggr-w7fw-pc2j
Fencer Vulns keeps one entry per vulnerability: the CVE id wins, then GHSA, and records that alias each other are merged, except that two CVEs always keep separate entries. The same data is available as JSON.