CVE-2026-107392: music-metadata Uncatchable Process Crash Parsing A Vulnerability

MODERATE
Advisory Identifier: GHSA-8j4c-6x6g-rq3j
CVSS 6.2
CWE-400 CWE-248
Published
Advisory Summary

CVE-2026-107392 is a MODERATE (CVSS 6.2) uncatchable process crash parsing a vulnerability (CWE-400: Uncontrolled Resource Consumption) affecting music-metadata libraries in the npm ecosystem. The issue involves uncatchable process crash parsing a crafted `.dsf` (residual of ghsa-v6c2-xwv6-8xf7). Remediation is available by upgrading affected packages to version 11.15.0.

CVE-2026-107392 at a Glance

CVE Identifier CVE-2026-107392
GHSA Identifier GHSA-8j4c-6x6g-rq3j
Severity MODERATE
CVSS v3.1 Base Score 6.2
CWE Classification CWE-400: Uncontrolled Resource Consumption
Affected Product music-metadata
Package Ecosystem npm
Published Date
Last Updated

Security Impact

CVSS: 6.2

The security impact metrics below are parsed directly from the CVSS v3.1 vector string (CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H).

Attack Vector Local (AV:L)
Attack Complexity Low (AC:L)
Privileges Required None (PR:N)
User Interaction None (UI:N)
Scope Unchanged (S:U)
Confidentiality None (C:N)
Integrity None (I:N)
Availability High (A:H)

How to Fix CVE-2026-107392

To remediate this vulnerability, upgrade all affected music-metadata dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.

music-metadata fixed: 11.15.0
npm install music-metadata@11.15.0
Verify Direct and Transitive Dependencies

Run the following command in your project directory to verify that all resolved dependencies use the patched release:

npm ls music-metadata

How to Check if You Are Affected

To determine whether your Node.js application is affected by CVE-2026-107392, inspect your project dependencies using npm:

npm ls music-metadata

Analyze the terminal output to locate any version of music-metadata in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 11.15.0), your application is affected.

Note: The npm ls music-metadata command inspects dependencies declared in your package.json and lockfile; it does not perform automated runtime dynamic scanning.

Technical Details

Vulnerability Mechanism & Technical Analysis

This vulnerability is classified under CWE-400: Uncontrolled Resource Consumption, where the product does not properly control the allocation and maintenance of a limited resource. In music-metadata, software state validation or input boundaries are circumvented during processing. Review the official source advisory statement below for specific affected components, classes, and reproduction details.

Source Advisory Statement

## 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

CVE-2026-107392 Affected music-metadata Versions

1 component(s)
Fixed Versions:
11.15.0
Product / Package Ecosystem Affected Versions Fixed Version
music-metadata
npm
< 11.15.0
11.15.0

References

Frequently Asked Questions

What is CVE-2026-107392?
CVE-2026-107392 is a security vulnerability in music-metadata involving uncatchable process crash parsing a crafted `.dsf` (residual of GHSA-v6c2-xwv6-8xf7) under CWE-400: Uncontrolled Resource Consumption.
Which music-metadata versions are affected?
Affected versions include releases prior to 11.15.0 across affected packages: music-metadata.
What version fixes CVE-2026-107392?
Upgrading to 11.15.0 (or the latest patched release for your respective branch) resolves the vulnerability.
Is music-metadata affected?
Yes, music-metadata is affected in releases prior to 11.15.0. Upgrade your dependency to 11.15.0 or later.
What is the CVSS score of CVE-2026-107392?
CVE-2026-107392 has a CVSS v3.1 base score of 6.2 (MODERATE) with vector string CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H.
What CWE is associated with CVE-2026-107392?
CVE-2026-107392 is classified under CWE-400: Uncontrolled Resource Consumption (The product does not properly control the allocation and maintenance of a limited resource.).
How can I check npm dependencies for CVE-2026-107392?
Run the dependency tree command: 'npm ls music-metadata'. This command lists direct and transitive dependencies in your build configuration so you can verify if a vulnerable version is resolved.
Machine-readable OSV JSON OSV v1.5 Schema
Normalized schema output
{
  "schema_version" : "1.4.0",
  "id" : "GHSA-8j4c-6x6g-rq3j",
  "modified" : "2026-10-08T19:40:45Z",
  "published" : "2026-10-08T19:40:45Z",
  "aliases" : [ "CVE-2026-107392" ],
  "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",
  "severity" : [ {
    "type" : "CVSS_V3",
    "score" : "CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H"
  } ],
  "affected" : [ {
    "package" : {
      "ecosystem" : "npm",
      "name" : "music-metadata"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "0"
      }, {
        "fixed" : "11.15.0"
      } ]
    } ],
    "database_specific" : {
      "last_known_affected_version_range" : "<= 11.14.0"
    }
  } ],
  "references" : [ {
    "type" : "WEB",
    "url" : "https://github.com/Borewit/music-metadata/security/advisories/GHSA-8j4c-6x6g-rq3j"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/Borewit/music-metadata/pull/2700"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/Borewit/music-metadata/commit/e7fc27a96e789d41ece41fdac590fc7618274a41"
  }, {
    "type" : "PACKAGE",
    "url" : "https://github.com/Borewit/music-metadata"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/Borewit/music-metadata/releases/tag/v11.15.0"
  } ],
  "database_specific" : {
    "cwe_ids" : [ "CWE-248", "CWE-400" ],
    "severity" : "MODERATE",
    "github_reviewed" : true,
    "github_reviewed_at" : "2026-10-08T19:40:45Z",
    "nvd_published_at" : null
  }
}