oss-sec mailing list archives

[NotCVE-2026-0019] game-music-emu through 0.6.5 VGM Command Interpreter Missing Operand Length Check Allows Heap Out-of-Bounds Read


From: advisories () notcve org
Date: Tue, 29 Sep 2026 10:31:38 +0200

----------------------------------------------------------------------------
NotCVE Advisory — NotCVE-2026-0019
----------------------------------------------------------------------------

[-] Summary:
An out-of-bounds read in the VGM command interpreter of game-music-emu
(libgme), the open-source video game music emulation library, allows an
attacker who supplies a crafted .vgm or .vgz file to read heap memory past
the end of the buffer holding the file. The read happens as soon as
playback begins. CVSS:3.1 5.4 (AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:N/A:L).

[-] Affected:
game-music-emu (libgme) through 0.6.5 (present in 0.6.0, 0.6.3 and 0.6.5),
and master as of commit fe8da4b. Default builds; no fixed version is
verified.

[-] Technical Description:
The command loop of Vgm_Emu_Impl::run_commands() (gme/Vgm_Emu_Impl.cpp) is
bounded only by

  while ( vgm_time < end_time && pos < data_end )

which validates the position of the opcode byte and nothing else. Each
opcode handler then fetches its operands from pos unconditionally. The
source records the gap in a TODO at the loop head: "be sure there are
enough bytes left in stream for particular command so we don't read past
end".

When a command stream ends right after an opcode byte, the operand fetch
crosses the end of the allocation made by Gme_File::load_(). Maximum
over-read per handler:

  - PSG and Game Gear register writes (*pos++): 1 byte
  - 16-bit delay 0x61 (pos[0], pos[1]): up to 2 bytes
  - YM2413 and YM2612 register writes: up to 2 bytes
  - PCM seek 0xE0 (pos[0] .. pos[3]): up to 4 bytes
  - data block header 0x67 (pos[1], get_le32( pos + 2 )): up to 6 bytes

The bytes read are consumed as sound-chip register data, so adjacent heap
contents can influence the decoded audio (limited, indirect disclosure).
AddressSanitizer aborts on the over-read; the researcher's two
proof-of-concept files reproduce it at two sites (a trailing 0x50 PSG
write and a trailing 0x67 data block header). Under a standard allocator a
read of this size normally stays within the same chunk, so a crash is
layout-dependent rather than reliable. No write, length control or code
execution is shown.

Reachability: VGM/VGZ support is in the default build. FFmpeg's
libavformat/libgme.c calls gme_open_data() and then gme_start_track()
inside read_header_gme(), so a server-side transcoder reaches the defect
while merely reading a file's header. VLC exposes the library through its
gme demux module, which handles VGM and VGZ.

Weaknesses:
CWE-125: Out-of-bounds Read
CWE-126: Buffer Over-read
CAPEC-540: Overread Buffers

[-] Credit:
Discovered by netspacer1124 (https://github.com/netspacer1124).

[-] Full Details and Updates:
https://notcve.org/notcve/NotCVE-2026-0019

[-] Main References:
https://github.com/libgme/game-music-emu
https://raw.githubusercontent.com/libgme/game-music-emu/0.6.5/gme/Vgm_Emu_Impl.cpp
https://ffmpeg.org/doxygen/5.1/libgme_8c_source.html

[-] About NotCVE:
NotCVE (https://notcve.org) assigns public, timestamped NotCVE IDs to
vulnerabilities not acknowledged by vendors. Vendor will not assign a CVE?
Request a NotCVE: https://notcve.org/form/ · Contributors:
https://notcve.org/hall/


Current thread: