Skip to content

mp4box.js short tkhd atom RangeError via unchecked fixed-field reads #564

Description

@hibrian827

Summary

mp4box.js accepts an undersized tkhd track-header atom through its public parsing API and dispatches it to tkhdBox.parse() without first proving that the atom body contains the fixed fields the parser will read. A crafted local MP4 with a moov/trak/tkhd chain whose tkhd payload contains only the FullBox version/flags bytes causes a deterministic DataView RangeError, which can turn media metadata parsing into an availability failure for services that process attacker-supplied MP4 files. This may have some secruity relevant issues, but as we failed to find any private means of contact, we decided to file this via github issue.

Affected

Root cause

The public entry point is createFile() in src/create-file.ts:9, which returns an ISOFile parser object used by callers to process MP4 data. ISOFile.appendBuffer() accepts caller-supplied bytes at src/isofile.ts:498 and immediately invokes parsing at src/isofile.ts:505. During generic box parsing, src/parser.ts:124 checks that the declared box size fits within the available stream, but that guard only validates containment; it does not validate the semantic minimum length of the concrete box type. Because the attacker-declared tkhd fourcc is registered, src/parser.ts:139 constructs the specialized box parser and src/parser.ts:173 calls box.parse(stream) without a tkhd-specific minimum-payload check. In src/boxes/tkhd.ts:21, tkhdBox.parse() reads the 4-byte FullBox header, then the version 0 path immediately reads creation_time with stream.readUint32() at src/boxes/tkhd.ts:30. For a tkhd body that ends immediately after the FullBox header, that reaches DataStream.readUint32() at src/DataStream.ts:454, whose underlying DataView.getUint32() throws once the current position is outside the available atom data.

Reproduction

poc.zip

bash ./poc/run.sh
RangeError: Offset is outside the bounds of the DataView at DataView.getUint32 (<anonymous>) at MultiBufferStream.readUint32 (file:///home/brian/work/variant-supreme/worktrees/exp-supreme-expansion_20260611T063343/runs/isobmff/INT-isobmff-mp4boxjs-short-tkhd-rangeerror/artifacts/positive/inputs/build-scratch/src/DataStream.js:351:34) at tkhdBox.parse

The RangeError plus the tkhdBox.parse frame shows that the malformed tkhd atom was accepted by the generic box parser and reached the fixed-field reads in the track-header parser. A setup or build failure would not include this parser frame and would not be evidence of this bug.

Suggested fix

diff --git a/src/boxes/tkhd.ts b/src/boxes/tkhd.ts
index 0d05e68..10e3fd9 100644
--- a/src/boxes/tkhd.ts
+++ b/src/boxes/tkhd.ts
@@ -19,7 +19,22 @@ export class tkhdBox extends FullBox {
   height: number;
 
   parse(stream: MultiBufferStream) {
+    if (this.size - this.hdr_size < 4) {
+      this.has_unparsed_data = true;
+      this.data = stream.readUint8Array(this.size - this.hdr_size);
+      return;
+    }
+
     this.parseFullHeader(stream);
+    const remaining = this.size - this.hdr_size;
+    const minimumFieldBytes = this.version === 1 ? 92 : 80;
+
+    if (remaining < minimumFieldBytes) {
+      this.has_unparsed_data = true;
+      this.data = stream.readUint8Array(remaining);
+      return;
+    }
+
     if (this.version === 1) {
       this.creation_time = stream.readUint64();
       this.modification_time = stream.readUint64();
       this.track_id = stream.readUint32();

Reported by Team Atlanta.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions