{"id":"GHSA-jggr-w7fw-pc2j","revision":null,"records":[{"revision":"733f89ad552547e9b7b319a5f3c10e63","observedAt":"2026-10-24T13:17:17.793+00:00","statement":{"source":"osv","id":"GHSA-jggr-w7fw-pc2j","aliases":[],"title":"fast-copy: Stack exhaustion in fast-copy when copying deeply-nested values","description":"## Summary\n\n`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.\n\n## Details\n\nBoth `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\nkilobytes of equivalent JSON.\n\nMeasured depths at which copying begins to fail (Node.js, V8; the exact ceiling varies with JIT state and the stack available to the environment):\n\n| Call                 | Last depth that copies successfully |\n| -------------------- | ----------------------------------- |\n| `copy(object)`       | 2811                                |\n| `copy(array)`        | 3983                                |\n| `copyStrict(object)` | 1874                                |\n| `copyStrict(array)`  | 1874                                |\n\n`JSON.parse` is iterative and parses deeply-nested input without difficulty, so a payload that deserializes cleanly can fail in a subsequent `copy` call.\n\n## Impact\n\nThe 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.\n\nApplications 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.\n\n## Patches\n\nFixed 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.\n\nTraversal 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.\n\nThe limit is configurable for consumers with legitimately deep data. On `3.x` and `4.x` it is set when creating a copier:\n\n```js\nimport { createCopier } from 'fast-copy';\n\nexport const copy = createCopier({ maxDepth: 5000 });\n```\n\nOn `2.x` it is passed per call, and the error is a property of the exported function rather than a named export:\n\n```js\nimport copy from 'fast-copy';\n\ncopy(value, { maxDepth: 5000 });\n// detection: error instanceof copy.MaxDepthExceededError\n```\n\nIn legacy environments without `Object.setPrototypeOf`, `instanceof MaxDepthExceededError` cannot be supported; check `error.name === 'MaxDepthExceededError'` or `error instanceof RangeError` instead.","state":0,"publishedAt":"2026-10-05T22:52:09+00:00","modifiedAt":"2026-10-05T23:00:05.4256431+00:00","affected":[{"ecosystem":"npm","name":"fast-copy","ranges":[{"type":"SEMVER","events":[{"kind":"introduced","version":"4.0.0"},{"kind":"fixed","version":"4.1.0"}]}],"versions":[],"rawVersionEvidence":null},{"ecosystem":"npm","name":"fast-copy","ranges":[{"type":"SEMVER","events":[{"kind":"introduced","version":"3.0.0"},{"kind":"fixed","version":"3.1.0"}]}],"versions":[],"rawVersionEvidence":null},{"ecosystem":"npm","name":"fast-copy","ranges":[{"type":"SEMVER","events":[{"kind":"introduced","version":"0"},{"kind":"fixed","version":"2.2.0"}]}],"versions":[],"rawVersionEvidence":null}],"metrics":[{"system":"CVSS_V4","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","score":null,"severity":null},{"system":"Publisher rating","vector":null,"score":null,"severity":"MODERATE"}],"references":["https://github.com/planttheidea/fast-copy/security/advisories/GHSA-jggr-w7fw-pc2j","https://github.com/planttheidea/fast-copy/pull/137","https://github.com/planttheidea/fast-copy/pull/138","https://github.com/planttheidea/fast-copy/pull/139","https://github.com/planttheidea/fast-copy/commit/359c00884ae8ae31f10925fd0e2fc66661db6cef","https://github.com/planttheidea/fast-copy/commit/caa7caace65767dfe252f0dc5115d82c99ca16b9","https://github.com/planttheidea/fast-copy/commit/dedf465e5329fbd149f13b53521af962d16ff8df","https://github.com/planttheidea/fast-copy","https://github.com/planttheidea/fast-copy/releases/tag/v2.2.0","https://github.com/planttheidea/fast-copy/releases/tag/v3.1.0","https://github.com/planttheidea/fast-copy/releases/tag/v4.1.0"],"sourceUrl":"https://github.com/advisories/GHSA-jggr-w7fw-pc2j","license":"GitHub Advisory Database · CC-BY-4.0","key":"osv:GHSA-jggr-w7fw-pc2j","identifiers":["GHSA-jggr-w7fw-pc2j"]},"retained":false,"historicalAffected":[]}],"coverage":[{"source":"cisa-kev:global","scope":"Complete CISA KEV catalog; all vendors. Missing entries do not establish absence of exploitation.","generation":"2026-11-11T15:59:29.1371819+00:00","complete":true,"records":1779,"lastAttemptAt":"2026-11-11T15:59:29.1371819+00:00","lastSuccessAt":"2026-11-11T15:59:29.3319702+00:00","error":null,"lastVerifiedAt":"2026-11-11T15:59:29.3319715+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"cve-program","scope":"Official CVE Program baseline and cumulative hourly delta; all vendors, published and rejected records","generation":"cve-de3b77103708811b6494d2ff7c979037d73ae579742cd1649a5c765137ae5083-f7a27b6686d027a29d541c1a67c85e77c8818c1542bd9e626ca104d5a08b6cff","complete":true,"records":424160,"lastAttemptAt":"2026-11-11T15:57:33.081355+00:00","lastSuccessAt":"2026-11-11T15:57:32.9249839+00:00","error":null,"lastVerifiedAt":"2026-11-11T15:57:33.081355+00:00","snapshotPublishedAt":"2026-11-11T15:27:38+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"euvd","scope":"Rolling EUVD lookups of CVE aliases in current public OSV archives; 500 identifiers per refresh, rechecked after 48 hours. Not a global EUVD catalog. Successful not-found lookups count as checked; they do not imply withdrawal or safety. No reader inventory is sent.","generation":"enrichment-fbe6382b6d1e4810ad598ca4b39b1839","complete":false,"records":13759,"lastAttemptAt":"2026-11-11T16:11:34.900804+00:00","lastSuccessAt":"2026-11-11T16:11:34.895+00:00","error":"8 identifier lookups failed; latest failures include HTTP 403. Other identifiers were checked independently.","lastVerifiedAt":"2026-11-11T16:11:34.895+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":13527,"expectedIdentifiers":13813,"failedIdentifiers":8},{"source":"first-epss:nuget","scope":"FIRST EPSS for explicit CVE aliases in the collected public NuGet archive. Not a global EPSS backfill.","generation":"2026-11-11T15:59:29.1371819+00:00","complete":true,"records":1097,"lastAttemptAt":"2026-11-11T15:59:29.1371819+00:00","lastSuccessAt":"2026-11-11T15:59:29.3328867+00:00","error":null,"lastVerifiedAt":"2026-11-11T15:59:29.332887+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"nvd","scope":"Rolling NVD lookups of CVE aliases in current public OSV archives; 500 identifiers per refresh, rechecked after 48 hours. Not a global NVD catalog. Successful not-found lookups count as checked; they do not imply withdrawal or safety. No reader inventory is sent.","generation":"enrichment-83d5ee721aa54b298ac0e478691d5c53","complete":true,"records":13753,"lastAttemptAt":"2026-11-11T15:59:30.4109764+00:00","lastSuccessAt":"2026-11-11T15:59:30.407+00:00","error":null,"lastVerifiedAt":"2026-11-11T15:59:30.407+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":13813,"expectedIdentifiers":13813,"failedIdentifiers":0},{"source":"osv:Go","scope":"Complete OSV Go ecosystem archive, including withdrawn and malicious-package source records; statement counts are not unique CVE counts","generation":"go-3562b6c78fd1bd0f0b55daf66a0926ae24f65e462df7f6d928caad458fc696bf","complete":true,"records":9947,"lastAttemptAt":"2026-11-11T15:59:28.9781944+00:00","lastSuccessAt":"2026-11-11T04:27:43.6877707+00:00","error":null,"lastVerifiedAt":"2026-11-11T15:59:28.9781944+00:00","snapshotPublishedAt":"2026-11-11T03:32:46+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"osv:NuGet","scope":"Complete OSV NuGet ecosystem archive, including GitHub Advisory Database records; NuGet version matching only","generation":"nuget-456002455e0ab94bb92c95476d4e6d175c104cd594749982afd96c893728ecbc","complete":true,"records":2010,"lastAttemptAt":"2026-11-11T15:57:33.229994+00:00","lastSuccessAt":"2026-11-11T02:36:58.1276999+00:00","error":null,"lastVerifiedAt":"2026-11-11T15:57:33.229994+00:00","snapshotPublishedAt":"2026-11-11T01:17:51+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"osv:crates.io","scope":"Complete OSV crates.io ecosystem archive, including withdrawn and malicious-package source records; statement counts are not unique CVE counts","generation":"crates.io-baa8362b4daf9e5f39d5563775a55935e7b442c0735d33274a921579ce4a0d66","complete":true,"records":3093,"lastAttemptAt":"2026-11-11T15:59:29.0795742+00:00","lastSuccessAt":"2026-11-11T13:00:02.5446881+00:00","error":null,"lastVerifiedAt":"2026-11-11T15:59:29.0795742+00:00","snapshotPublishedAt":"2026-11-11T12:47:47+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"osv:npm","scope":"Complete OSV npm ecosystem archive, including withdrawn and malicious-package source records; statement counts are not unique CVE counts","generation":"npm-eb69eb75f2b568fd8be458efa2db8e11aac201724ba0b44fa3f79c386f195e15","complete":true,"records":231668,"lastAttemptAt":"2026-11-11T15:59:28.847182+00:00","lastSuccessAt":"2026-11-11T15:59:27.3458308+00:00","error":null,"lastVerifiedAt":"2026-11-11T15:59:28.847182+00:00","snapshotPublishedAt":"2026-11-11T15:33:06+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null}]}