Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

Two OOB reads in L3_huffman main_data buffer access — redirected from mackron/dr_libs

Open
#145 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
4/5
Estimated time
3-5 days
Newbie friendliness
50/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Quiet
Tech stack
c
Domain
security

Research direction

Both reads live in L3_huffman at minimp3.h:742: the CHECK_BITS macro at :767 (invoked at :810, :818, :846, :873) and the four-byte bs_cache prefill at :773-774. First read how bs->buf, bs->pos and bs->limit are maintained, and note the only existing guard in the function, if (BSPOS > layer3gr_limit) break; at :861, sits in the count1 path after big_values has exited. Gate both reads on the buffer end, then confirm ordinary MP3s decode unchanged using the repo's existing test files, since the PoC inputs are not public.

Written by the indexing model from the issue text.

Description

Hello lieff,

Reporting two heap OOB read vulnerabilities in L3_huffman
(minimp3.h:742) — both involve unchecked reads via bs_next_ptr,
a pointer that walks through the maindata bitstream buffer. They were originally found in
mackron/dr_libs (where this code is forked as drmp3_L3_huffman in
dr_mp3.h). David Reid (mackron) acknowledged the reports on 2026-04-25
and asked us to redirect them upstream:

> "The decoders for these are taken straight from minimp3 so I'm
>  not too sure how I want to handle this. ... I think it's probably
>  best you report this to the upstream project, lieff/minimp3."
> — David Reid, 2026-04-25

We grouped the two issues into a single report because they share the
same function (L3_huffman), the same buffer (bs_next_ptr walking
through maindata), and the same root cause (no bounds enforcement on
bs_next_ptr against the buffer end). Happy to split into two issues
if you prefer.

These are distinct from existing minimp3 issues we reviewed:
- #122 (shift UB at minimp3.h:379, 649): Layer 1/2 requantize —
DIFFERENT function and bug class.
- #134 (Xing/Info OOB, ByamB4 2026-02-17): mp3dec_check_vbrtag —
DIFFERENT function (overlaps separately with our dr_libs Advisory
5, which mackron fixed in dr_mp3 commit ea24c1f; minimp3-side
fix is pending).
- #140 (Xing/Info int overflow, HOHK0923 2026-03-13): same
Xing/Info extension layer as #134, DIFFERENT from L3_huffman.
- #144 (vague heap overflow, programmervuln 2026-04-23): private
body. We could not determine overlap from the public metadata;
please flag if it does and we will close as duplicate.

=== Issue 1: CHECK_BITS macro advances bs_next_ptr without bounds check (dr_libs Advisory #1) ===

Affected: L3_huffman (minimp3.h:742), big_values decoding loop
Location: macro definition at minimp3.h:767, invoked at minimp3.h:810,
818, 846 (big_values paths) and 873 (count1 path)
Severity: High (CVSS ~8.6 in our analysis; please re-rate as you
see fit)
CWE: CWE-125 (Out-of-bounds Read)

Vulnerable code (minimp3.h verbatim):

  // minimp3.h:767
  #define CHECK_BITS    while (bs_sh >= 0) { bs_cache |= (uint32_t)*bs_next_ptr++ << bs_sh; bs_sh -= 8; }

The macro unconditionally advances bs_next_ptr while bs_sh >= 0,
with no check against the end of the maindata buffer. During
big_values Huffman decoding of a crafted MP3 file (where pos drifts
beyond the granule's main_data extent), this reads heap memory past
the bitstream buffer end.

The only BSPOS bound check we found in L3_huffman is in the count1
section (minimp3.h:861 — if (BSPOS > layer3gr_limit) break;), which
runs after the big_values loop has already exited. The big_values
section itself (minimp3.h:778–850) has no equivalent guard before each
CHECK_BITS invocation.

Impact: Heap out-of-bounds read. An attacker supplying a crafted MP3
may read out-of-bounds heap memory beyond the bitstream buffer.
Reachable from any untrusted MP3 input via public
mp3dec_decode_frame / mp3dec_load_* APIs.

Suggested fix: gate CHECK_BITS on bs_next_ptr < bs_end (passing
bs_end = bs->buf + bs->limit/8 + 1 or equivalent), e.g.:

  #define CHECK_BITS \
      while (bs_sh >= 0 && bs_next_ptr < bs_end) { \
          bs_cache |= (uint32_t)*bs_next_ptr++ << bs_sh; \
          bs_sh -= 8; \
      }

=== Issue 2: 4-byte cache prefill OOB read at L3_huffman entry (dr_libs Advisory #8) ===

Affected: L3_huffman (minimp3.h:742), bs_cache initialization
Location: minimp3.h:773–774 (4-byte read at function entry, before
any CHECK_BITS invocation — distinct from Issue 1)
Severity: High (CVSS ~7.5 in our analysis; please re-rate as you see
fit)
CWE: CWE-125 (Out-of-bounds Read)

Vulnerable code (minimp3.h verbatim):

  // minimp3.h:773
  const uint8_t *bs_next_ptr = bs->buf + bs->pos/8;
  // minimp3.h:774
  uint32_t bs_cache = (((bs_next_ptr[0]*256u + bs_next_ptr[1])*256u + bs_next_ptr[2])*256u + bs_next_ptr[3]) << (bs->pos & 7);

The function entry unconditionally reads bs_next_ptr[0..3] (4 bytes)
without checking that 4 bytes remain in the buffer past bs->pos/8.
When the buffer layout leaves fewer than 4 bytes at the entry position,
this reads past the end before the big_values loop is even entered.
This is independent of Issue 1 — it triggers on the very first
function call of a granule, not during the loop.

Impact: Heap out-of-bounds read of 1–3 bytes (depending on remaining
buffer space at entry).

Suggested fix: validate that at least 4 bytes remain past bs->pos/8
at entry, or use a guarded byte-by-byte cache fill that respects the
buffer end.

=== Reproducer ===

We have proof-of-concept inputs for the dr_mp3 fork that trigger both
reads under AddressSanitizer. Since the dr_mp3 Huffman decoder is the
same code as minimp3's L3_huffman, we infer the same inputs would
reproduce on minimp3 with a thin driver (we have not run them against
lieff/minimp3 directly). Happy to share the inputs (and the fuzzing
harness) privately — please reply with a preferred channel (e.g.,
email at [email protected], or any other private channel you prefer).
We will not post the inputs in this issue while a fix is in progress.

=== Discovery method ===

Found via cross-model AI security review (Claude + GPT + Gemini,
independent analyses combined into a Union of findings) targeting
mackron/dr_libs commit 4d74802. Eight advisories were reported to
mackron on 2026-04-07; six are now resolved on the dr_libs side, two
(these two) are redirected here per David's note.

Thanks for maintaining minimp3.

Best,
Song Tae-Eun
[email protected]

Dominant language
C
Stars
2k
Forks
271
PR merge metrics
No merged PRs in 30d

Getting set up

This project ships no dev container, Dockerfile or contributing guide, so setting up is up to you: start from its README, and see our first-contribution guide for the general steps.

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from lieff/minimp3

All issues in lieff/minimp3

Similar issues

More C issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.