Skip to content

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

@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

N/A — fixture committed in PR #2669 (packages/alphatab/test-data/guitarpro5/chord-name-overflow.gp5).

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)

The bug is on the importer side, so it surfaces on every platform that consumes the resulting Score — Web, Node.js, .NET, Android, iOS all affected equally. Reproducer environment above is just where I observed it.

Platform

Node.js

Anything else?

After-fix validation: the fixture's beat-by-beat byte position matches PyGuitarPro 1217/1217 beats. Fix proposed in PR #2669. Two related bugs from the same area (#2671, #2673) are tracked separately.

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