GHSA-8j4c-6x6g-rq3j: Medium severity npm/music-metadata vulnerability

Published Oct 8, 2026
·
Updated

Summary DsfParser.parseChunks skips an unrecognised chunk's payload with an un-awaited call: js this.tokenizer.ignore(Number(chunkHeader.size) - ChunkHeader.len); // lib/dsf/DsfParser.js:51 — no await ChunkHeader.len is 12. A crafted .dsf chunk with id != 'fmt ' and size in 0..11 makes the argument negative; strtok3 (≥ 10.3.5) throws RangeError on a negative ignore. Because the call is fire-and-forget, the rejection is detached from the parseBuffer() promise chain → unhandled rejection → Node's default (≥ 15) crashes the process — after parseBuffer() already resolved, so a caller's try/catch catches nothing and is still taken down.

Residual of GHSA-v6c2-xwv6-8xf7: the ASF site was fixed in 11.12.3 (size validation) and strtok3 now throws on negative ignore; the DSF site was never validated, and its missing await escalates that throw into an uncatchable crash.

Root cause (lib/dsf/DsfParser.js:34-56) js while (bytesRemaining >= ChunkHeader.len) { // ChunkHeader.len = 12 const chunkHeader = await this.tokenizer.readToken(ChunkHeader); // { id, size } switch (chunkHeader.id) { case 'fmt ': { ...; return; } default: this.tokenizer.ignore(Number(chunkHeader.size) - ChunkHeader.len); break; // size<12 -> negative, no await } bytesRemaining -= chunkHeader.size; } strtok3 AbstractTokenizer.ignore (L78-79): if (length < 0) throw new RangeError('ignore length must be ≥ 0 bytes');

Steps to reproduce repro/ — public API only, Node's default unhandled-rejection mode, try/catch around the parse: npm install && node poc.mjs Confirmed on 11.14.0: [app] parseBuffer() RESOLVED — the caller saw no error to catch. RangeError: ignore length must be ≥ 0 bytes at DsfParser.parseChunks (.../lib/dsf/DsfParser.js:51) <process exits non-zero — the "process survived" line never prints>

Impact DoS: a single crafted .dsf (or any file with the DSD magic) crashes the Node process of any app parsing untrusted audio with music-metadata (2.2M weekly downloads). The crash bypasses the caller's error handling, so even apps that correctly try/catch per-file parsing are killed — one malicious upload can take down a shared server/worker.

Remediation Add await on line 51 (makes the RangeError a catchable parse error), and validate chunkHeader.size >= ChunkHeader.len before the skip (as the ASF fix did; also guards the loop counter). Audit other parsers for un-awaited tokenizer.ignore()/readToken().

Scope / honesty Requires the DSF path (a DSD -magic file — normal auto-detection). Relies on Node's default unhandled-rejection mode (throw, default since Node 15); the point is that the standard defensive per-parse try/catch does not protect against it. Crash (availability), not disclosure/RCE. Negatives confirmed alongside: ASF infinite loop fixed; negative-ignore infinite-loop class closed at strtok3; unbounded allocation bounded by strtok3's read bound-check.

Credits Issue also reported by @ryu7eroo

Affected Software

1 affected componentFixes available
npm/music-metadata<=11.14.0
11.15.0

Remediation

Recommended actions to resolve this vulnerability, in priority order.

  1. Upgrade

    Upgrade npm/music-metadata to a version that resolves this vulnerability.

    Fixed in 11.15.0
  2. Compensating control

    In DsfParser.parseChunks, await the tokenizer.ignore() call for unrecognised chunks and validate that chunkHeader.size >= ChunkHeader.len before skipping the payload; ChunkHeader.len is 12.

  3. Compensating control

    Audit other parsers for un-awaited tokenizer.ignore() and readToken() calls so parser errors remain attached to the parse promise chain.

Event History

Oct 8, 2026
Advisory Published
via GitHub·07:40 PM
Data Sourced
via GitHub·07:40 PM
DescriptionSeverityWeaknessAffected Software

Frequently Asked Questions

1

Which deployments are exposed to a process crash?

Deployments that parse crafted .dsf files with music-metadata are exposed. The described crash behavior applies to Node.js 15 and later, where an unhandled rejection crashes the process by default.

2

What does an attacker need to include in a DSF file to trigger the failure?

The file must contain an unrecognised DSF chunk whose size field is between 0 and 11 inclusive. This causes the parser to call ignore with a negative value, which strtok3 version 10.3.5 or later rejects with a RangeError.

3

Can an application catch this failure by wrapping parseBuffer() in try/catch?

No. The parser invokes the failing ignore call without awaiting it, so parseBuffer() can resolve before the rejection occurs; the rejection is detached from the returned promise chain and is not caught by the caller's try/catch.

Contact

SecAlerts Pty Ltd.
132 Wickham Terrace
Fortitude Valley,
QLD 4006, Australia
info@secalerts.co
By using SecAlerts services, you agree to our services end-user license agreement. This website is safeguarded by reCAPTCHA and governed by the Google Privacy Policy and Terms of Service. All names, logos, and brands of products are owned by their respective owners, and any usage of these names, logos, and brands for identification purposes only does not imply endorsement. If you possess any content that requires removal, please get in touch with us.
© 2026 SecAlerts Pty Ltd.
ABN: 70 645 966 203, ACN: 645 966 203