Talos Vulnerability Report

TALOS-2026-2441

mackron dr_libs dr_mp3 drmp3_init_internal out-of-bounds read vulnerability

November 10, 2026

CVE Number

CVE-2026-11315

Summary

A out-of-bounds read vulnerability exists in the dr_mp3 drmp3_init_internal functionality of dr_libs (version(s): 0.7.3). A specially crafted .mp3 file can lead to an out-of-bounds read. An attacker can provide a malicious file to trigger this vulnerability.

Confirmed Vulnerable Versions

The versions below were either tested or verified to be vulnerable by Talos or confirmed to be vulnerable by the vendor.

dr_libs (version(s): 0.7.3)

Product URLs

dr_libs - https://github.com/mackron/dr_libs

CVSSv3 Score

4.3 - CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:N/A:N

CWE

CWE-125 - Out-of-bounds Read

Details

dr_libs is a collection of high-quality, single-file audio decoding libraries for C and C++, developed by David Reid (mackron). It is popular in the game development and embedded systems communities because it is extremely easy to integrate.

dr_mp3 is the MPEG Layer III (MP3) decoder from that collection. It is a single header that drops into any project needing MP3 playback without extra build steps and is widely used in games, audio tools and media applications.

Frame sync detection is the first step when dr_mp3 processes input. The decoder scans for a valid MPEG frame header by checking the sync word and validating the layer, bitrate and sample-rate fields through drmp3_hdr_valid at [1]:

static int drmp3_hdr_valid(const drmp3_uint8 *h)
{
    return h[0] == 0xff && [1]
        ((h[1] & 0xF0) == 0xf0 || (h[1] & 0xFE) == 0xe2) &&
        (DRMP3_HDR_GET_LAYER(h) != 0) &&
        (DRMP3_HDR_GET_BITRATE(h) != 15) &&
        (DRMP3_HDR_GET_SAMPLE_RATE(h) != 3);
}

Once a valid frame header is found, drmp3_init_internal reads the first frame and parses the MPEG side information to locate a potential Xing or Info VBR tag. The side information tells the decoder where the audio payload begins within the frame. Parsing is driven by drmp3_L3_read_side_info, a bitstream reader that advances its own bit position bs.pos independently of the frame’s allocation size.

After side info parsing, pTagData is computed by adding the byte offset bs.pos/8 to the frame base at [2] and the 4-byte Xing/Info identifier is read through that pointer at [3]. No bounds check ensures that pTagData still points within the allocated frame buffer:

drmp3_bs_init(&bs, pFirstFrameData + DRMP3_HDR_SIZE, firstFrameInfo.frame_bytes - DRMP3_HDR_SIZE);

if (DRMP3_HDR_IS_CRC(pFirstFrameData)) {
    drmp3_bs_get_bits(&bs, 16); /* CRC. */
}

if (drmp3_L3_read_side_info(&bs, grInfo, pFirstFrameData) >= 0) {
    drmp3_bool32 isXing = DRMP3_FALSE;
    drmp3_bool32 isInfo = DRMP3_FALSE;
    const drmp3_uint8* pTagData;
    const drmp3_uint8* pTagDataBeg;

    pTagDataBeg = pFirstFrameData + DRMP3_HDR_SIZE + (bs.pos/8); [2]
    pTagData = pTagDataBeg;

    /* Check for both "Xing" and "Info" identifiers. */
    isXing = (pTagData[0] == 'X' && pTagData[1] == 'i' && pTagData[2] == 'n' && pTagData[3] == 'g'); [3]
    isInfo = (pTagData[0] == 'I' && pTagData[1] == 'n' && pTagData[2] == 'f' && pTagData[3] == 'o');

With a truncated frame, side info parsing advances bs.pos to a bit position whose byte offset bs.pos/8 exceeds firstFrameInfo.frame_bytes - DRMP3_HDR_SIZE, so pTagData lands past the end of the heap-allocated frame buffer before any guard runs. The pTagData[0] access at [3] is therefore the first read off the end of the allocation and the subsequent pTagData[1..3] comparisons continue past it.

AddressSanitizer confirms a heap-buffer-overflow READ of 1 byte at drmp3_init_internal. The faulting address is 0 bytes after a 46-byte heap region (the first byte past the frame allocation), matching the pTagData[0] dereference at [3]. The crafted MP3 wraps a truncated MPEG 2.5 Layer III frame that is too short to contain both the side information and the 4-byte tag identifier:

Crash Information

==382003==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x7c3ff6fe003e at pc 0x000000506937 bp 0x7fffffffb670 sp 0x7fffffffb668
READ of size 1 at 0x7c3ff6fe003e thread T0
    #0 0x000000506936 in drmp3_init_internal dr_mp3.h:3192:27
    #1 0x00000050774a in drmp3_init_memory_with_metadata dr_mp3.h:3390:14
    #2 0x000000513238 in drmp3_init_memory dr_mp3.h:3409:12
    #3 0x000000513238 in main harness_replay.c:44:7
    #4 0x7ffff7c785b4 in __libc_start_call_main (/lib64/libc.so.6+0x35b4) (BuildId: ff0267465bc3d76e21003b3bc5598fd5ee63e261)
    #5 0x7ffff7c78667 in __libc_start_main@GLIBC_2.2.5 (/lib64/libc.so.6+0x3667) (BuildId: ff0267465bc3d76e21003b3bc5598fd5ee63e261)
    #6 0x000000400704 in _start (build/target.asan+0x400704) (BuildId: 5eb8a7784f372cf93e98345dc74f9115937900e5)

0x7c3ff6fe003e is located 0 bytes after 46-byte region [0x7c3ff6fe0010,0x7c3ff6fe003e)
allocated by thread T0 here:
    #0 0x0000004a5bf8 in malloc (build/target.asan+0x4a5bf8) (BuildId: 5eb8a7784f372cf93e98345dc74f9115937900e5)
    #1 0x0000005131dd in main harness_replay.c:35:24
    #2 0x7ffff7c785b4 in __libc_start_call_main (/lib64/libc.so.6+0x35b4) (BuildId: ff0267465bc3d76e21003b3bc5598fd5ee63e261)
    #3 0x7ffff7c78667 in __libc_start_main@GLIBC_2.2.5 (/lib64/libc.so.6+0x3667) (BuildId: ff0267465bc3d76e21003b3bc5598fd5ee63e261)
    #4 0x000000400704 in _start (build/target.asan+0x400704) (BuildId: 5eb8a7784f372cf93e98345dc74f9115937900e5)

SUMMARY: AddressSanitizer: heap-buffer-overflow dr_mp3.h:3192:27 in drmp3_init_internal
  0x7c3ff6fdfd80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x7c3ff6fdfe00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x7c3ff6fdfe80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x7c3ff6fdff00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x7c3ff6fdff80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x7c3ff6fe0080: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x7c3ff6fe0100: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x7c3ff6fe0180: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x7c3ff6fe0200: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x7c3ff6fe0280: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
==382003==ABORTING

Vendor Response (CVE-2026-11315)

Vendor Link: https://github.com/mackron/dr_libs

Vendor Notes: Vendor had not replied. Please check their GitHub repository for latest release and information regarding the product.

Timeline

2026-07-02 - Cisco - Vendor Notification
2026-07-16 - Cisco - Follow-up sent
2026-09-15 - Cisco - Follow-up sent
2026-11-10 - Cisco - Published

Credit

Ankur Tyagi of Cisco Talos