{"schema":"threatline.record/2","record":{"id":"CVE-2026-107392","aliases":["GHSA-8j4c-6x6g-rq3j"],"summary":"music-metadata: uncatchable process crash parsing a crafted `.dsf` (residual of GHSA-v6c2-xwv6-8xf7)","details":"## Summary\n`DsfParser.parseChunks` skips an unrecognised chunk's payload with an **un-awaited** call:\n```js\nthis.tokenizer.ignore(Number(chunkHeader.size) - ChunkHeader.len);   // lib/dsf/DsfParser.js:51 — no await\n```\n`ChunkHeader.len` is 12. A crafted `.dsf` chunk with `id != 'fmt '` and `size` in `0..11` makes the\nargument negative; strtok3 (≥ 10.3.5) throws `RangeError` on a negative `ignore`. Because the call\nis fire-and-forget, the rejection is **detached from the `parseBuffer()` promise chain** → unhandled\nrejection → Node's default (≥ 15) **crashes the process** — **after** `parseBuffer()` already\nresolved, so a caller's `try/catch` catches nothing and is still taken down.\n\nResidual of GHSA-v6c2-xwv6-8xf7: the ASF site was fixed in 11.12.3 (size validation) and strtok3\nnow throws on negative `ignore`; the DSF site was never validated, and its missing `await`\nescalates that throw into an **uncatchable** crash.\n\n## Root cause (`lib/dsf/DsfParser.js:34-56`)\n```js\nwhile (bytesRemaining >= ChunkHeader.len) {               // ChunkHeader.len = 12\n  const chunkHeader = await this.tokenizer.readToken(ChunkHeader);   // { id, size }\n  switch (chunkHeader.id) {\n    case 'fmt ': { ...; return; }\n    default: this.tokenizer.ignore(Number(chunkHeader.size) - ChunkHeader.len); break;  // size<12 -> negative, no await\n  }\n  bytesRemaining -= chunkHeader.size;\n}\n```\nstrtok3 `AbstractTokenizer.ignore` (L78-79): `if (length < 0) throw new RangeError('ignore length must be ≥ 0 bytes');`\n\n## Steps to reproduce\n`repro/` — public API only, Node's default unhandled-rejection mode, `try/catch` around the parse:\n```\nnpm install && node poc.mjs\n```\nConfirmed on 11.14.0:\n```\n[app] parseBuffer() RESOLVED — the caller saw no error to catch.\nRangeError: ignore length must be ≥ 0 bytes\n    at DsfParser.parseChunks (.../lib/dsf/DsfParser.js:51)\n   <process exits non-zero — the \"process survived\" line never prints>\n```\n\n## Impact\nDoS: a single crafted `.dsf` (or any file with the `DSD ` magic) crashes the Node process of any\napp parsing untrusted audio with music-metadata (2.2M weekly downloads). The crash bypasses the\ncaller's error handling, so even apps that correctly `try/catch` per-file parsing are killed — one\nmalicious upload can take down a shared server/worker.\n\n## Remediation\nAdd `await` on line 51 (makes the `RangeError` a catchable parse error), and validate\n`chunkHeader.size >= ChunkHeader.len` before the skip (as the ASF fix did; also guards the loop\ncounter). Audit other parsers for un-awaited `tokenizer.ignore()`/`readToken()`.\n\n## Scope / honesty\nRequires the DSF path (a `DSD `-magic file — normal auto-detection). Relies on Node's default\nunhandled-rejection mode (`throw`, default since Node 15); the point is that the standard defensive\nper-parse `try/catch` does not protect against it. Crash (availability), not disclosure/RCE.\nNegatives confirmed alongside: ASF infinite loop fixed; negative-`ignore` infinite-loop class\nclosed at strtok3; unbounded allocation bounded by strtok3's read bound-check.\n\n## Credits\nIssue also reported by @ryu7eroo","categories":["Libraries & packages"],"product":"music-metadata","vendor":"Borewit","ecosystem":"npm","affected_ranges":[{"source":"GitHub Advisory Database","source_url":"https://github.com/advisories/GHSA-8j4c-6x6g-rq3j","source_modified_at":"2026-10-08T19:40:46Z","fetched_at":"2026-10-23T18:42:43.628194Z","package":{"ecosystem":"npm","name":"music-metadata"},"range":"<= 11.14.0"},{"source":"CVE List","source_url":"https://www.cve.org/CVERecord?id=CVE-2026-107392","source_modified_at":"2026-10-08T19:53:23.640Z","fetched_at":"2026-10-23T18:45:31.882637Z","product":"music-metadata","vendor":"Borewit","versions":[{"version":"< 11.15.0","status":"affected"}],"defaultStatus":null},{"source":"OSV","source_url":"https://osv.dev/vulnerability/GHSA-8j4c-6x6g-rq3j","source_modified_at":"2026-10-08T20:00:05.860263177Z","fetched_at":"2026-10-23T18:45:31.882637Z","package":{"name":"music-metadata","ecosystem":"npm","purl":"pkg:npm/music-metadata"},"ranges":[{"type":"SEMVER","events":[{"introduced":"0"},{"fixed":"11.15.0"}]}],"versions":[]}],"fixed_versions":[{"source":"GitHub Advisory Database","source_url":"https://github.com/advisories/GHSA-8j4c-6x6g-rq3j","source_modified_at":"2026-10-08T19:40:46Z","fetched_at":"2026-10-23T18:42:43.628194Z","package":{"ecosystem":"npm","name":"music-metadata"},"version":"11.15.0"},{"source":"OSV","source_url":"https://osv.dev/vulnerability/GHSA-8j4c-6x6g-rq3j","source_modified_at":"2026-10-08T20:00:05.860263177Z","fetched_at":"2026-10-23T18:45:31.882637Z","package":{"name":"music-metadata","ecosystem":"npm","purl":"pkg:npm/music-metadata"},"version":"11.15.0"}],"cvss":6.2,"severity":"Medium","kev":{"listed":false},"epss":{"probability":0.00355,"percentile":0.28061,"score_date":"2026-10-23"},"published_at":"2026-10-08T19:13:06.392Z","modified_at":"2026-10-08T20:00:05.860263177Z","provenance":[{"source":"GitHub Advisory Database","url":"https://github.com/advisories/GHSA-8j4c-6x6g-rq3j","fetched_at":"2026-10-23T18:42:43.628194Z","source_modified_at":"2026-10-08T19:40:46Z"},{"source":"CVE List","url":"https://www.cve.org/CVERecord?id=CVE-2026-107392","fetched_at":"2026-10-23T18:45:31.882637Z","source_modified_at":"2026-10-08T19:53:23.640Z"},{"source":"OSV","url":"https://osv.dev/vulnerability/GHSA-8j4c-6x6g-rq3j","fetched_at":"2026-10-23T18:45:31.882637Z","source_modified_at":"2026-10-08T20:00:05.860263177Z"},{"source":"EPSS","url":"https://api.first.org/data/v1/epss?cve=CVE-2026-107392","fetched_at":"2026-10-23T18:42:43.628194Z","source_modified_at":"2026-10-23"}],"sources":["GitHub Advisory Database","CVE List","OSV","EPSS"],"references":[{"source":"CVE List","url":"https://github.com/Borewit/music-metadata/security/advisories/GHSA-8j4c-6x6g-rq3j","tags":["exploit"]},{"source":"CVE List","url":"https://github.com/Borewit/music-metadata/pull/2700","tags":["x_refsource_MISC"]},{"source":"CVE List","url":"https://github.com/Borewit/music-metadata/commit/e7fc27a96e789d41ece41fdac590fc7618274a41","tags":["x_refsource_MISC"]},{"source":"CVE List","url":"https://github.com/Borewit/music-metadata/releases/tag/v11.15.0","tags":["x_refsource_MISC"]},{"url":"https://github.com/advisories/GHSA-8j4c-6x6g-rq3j","source":"GitHub Advisory Database"}],"locations":[],"motoko_assessment":{"status":"requires_architecture_review","automatic_remediation":false},"cve_state":"PUBLISHED","ssvc":{"exploitation":"poc","automatable":"no","technical_impact":"partial","assessed_at":"2026-10-08T19:53:02.846447Z"},"classification":{"method":"product-first software-layer rules","rules_version":"2.1","matched_on":"ecosystem","confidence":"heuristic","reviewed":false},"change_timestamp":"2026-10-08T20:00:05.860263177Z","content_hash":"cda295b4056d5febcec38d4eea1485d03741ce9886f447ab31e6c19f00fe8af0"}}
