Skip to content

gpReadStringByteLength misaligns parser on oversized chord-name length hint (DoS) #2676

@kaizenman

Description

@kaizenman

Is there an existing issue for this?

  • I have searched the existing issues

Current Behavior

GpBinaryHelpers.gpReadStringByteLength (in Gp3To5Importer) treats the length-hint byte as the actual byte count to read, then skips to a fixed-width boundary:

const stringLength: number = data.readByte();
const s: string = GpBinaryHelpers.gpReadString(data, stringLength, encoding);
if (stringLength < length) {
    data.skip(length - stringLength);
}

When the hint exceeds the field width — which happens in real-world Guitar Pro 5 files where a user typed a chord-comment string longer than the on-disk field (the editor allows it; the file stores the original length byte verbatim with the data truncated) — the read advances stringLength bytes, overshooting the field by stringLength - length. The remainder of the beat parse is then misaligned.

Concrete failure mode: misalignment lands inside readBend, which interprets garbage as a 4-byte pointCount, enters a tight loop reading 9 bytes per iteration, and burns the V8 heap.

  • Node: OOM-crash after 5–30 seconds.
  • Browser: tab deadlocks at 100% CPU and eventually crashes the renderer (taking down sibling tabs in the same Chromium process).

This is a practical denial-of-service vector against any page that runs AlphaTab on user-supplied .gp5 input.

Expected Behavior

The function should read a fixed-width field (length bytes) and decode up to min(stringLength, length) of those bytes — matching the way PyGuitarPro (readByteSizeString(count)) and TuxGuitar (readStringByte(size)) handle the same field. With this semantic, oversized length hints decode cleanly and the rest of the beat parse stays aligned.

Steps To Reproduce

  1. Obtain a Guitar Pro 5 file with a chord-comment field where the length byte exceeds the field width. Reference fixture: test-data/guitarpro5/chord-name-overflow.gp5 (a published GP 5.10 file with stringLength=32 in a 22-byte field). Fixture is committed in PR fix(importer): cap chord name read at field width in GP3-5 binary parser #2669.
  2. Run ScoreLoader.loadScoreFromBytes(bytes) in Node.
  3. Observe Node OOM-crash after several seconds (V8 reports Reached heap limit Allocation failed).

Link to jsFiddle, CodePen, Project

No response

Version and Environment

alphaTab: 1.9.0 (commit f8ef24f, current HEAD of `develop`)
Node.js: v22.14.0
OS: Ubuntu 22.04.3 LTS on WSL2 (kernel 6.6.87.2-microsoft-standard-WSL2)

Platform

Web

Anything else?

No response

Metadata

Metadata

Assignees

Labels

area-file-formatsRelated to supported file formatsplatform-allAffects all platformsstate-acceptedThis is a valid topic to work on.

Type

Projects

Status

No status

Relationships

None yet

Development

No branches or pull requests

Issue actions