GROK-0013
low harness-verifiedMJ2 read_url/read_urn: NULL-pointer dereference of current_track_ when a dref/url box has no preceding tkhd
⚠ Harness reproduced — not real-world verified. Reproduce through the public API, a real application, or a platform decoder before treating this as verified.
Classification
| Target | Grok |
|---|---|
| Component | JP2 file format |
| Location | src/lib/core/fileformat/decompress/FileFormatMJ2Decompress.cpp · read_url / read_urn:351,377 |
| Vuln class | dos |
| CVE | — |
| CVSS | 4 (CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H) |
| Discovered | 2026-06-16 |
Verification
| Evidence | Harness reproduced (not real-world verified) |
|---|---|
| Harness fired | ✅ yes |
| Protocol | 1.0 |
| Sanitizer | asan |
| Crash type | SEGV / NULL-pointer dereference |
| Repro | clang-20 + libc++ ASAN build; grk_decompress -i pocs/grok/GROK-0013/poc.mj2 → ASAN SEGV (READ, near-null addr 0x40) at read_url (FileFormatMJ2Decompress.cpp:351, current_track_->url_.push_back) <- read_dref:400 <- readHeaderProcedure. |
Disclosure
| Reported to | Grok maintainers — support@grokcompression.com (private email; repo has no Private Vulnerability Reporting / SECURITY.md) |
|---|---|
| Reported | 2026-06-23 |
| Vendor ack | — |
| Embargo until | — |
| Public | 2026-06-24 |
| Patched in | — |
PoC: pocs/grok/GROK-0013/poc.mj2
Writeup
Summary
read_url (line 351, current_track_->url_.push_back(url)) and read_urn (line 377) dereference
current_track_ without a null check. current_track_ is only set by read_tkhd. The MJ2 box
reader recurses structurally into minf/dinf/dref regardless of whether a tkhd has been seen, so
a crafted MJ2 with a dref→url box and no preceding tkhd reaches read_url with
current_track_ == nullptr → null-pointer dereference / crash.
bool read_url(uint8_t* headerData, uint32_t headerSize) {
read_version_and_flag(&headerData, version, flag);
headerSize -= 4;
if(flag != 1) {
mj2_url url; ... grk_read(... url.location_ ...);
current_track_->url_.push_back(url); // :351 current_track_ may be null
}
}
Reproduction
VERIFIED. pocs/grok/GROK-0013/poc.mj2 (96 bytes): ftyp(mjp2) + moov/trak/mdia/minf/dinf/dref/url,
with no tkhd. grk_decompress -i pocs/grok/GROK-0013/poc.mj2 -o /tmp/o.png.
Root cause
read_url/read_urn assume a track has been created; the parser does not enforce tkhd before
dref, and there is no null guard on current_track_.
Verification evidence
VERIFIED under AddressSanitizer (2026-06-16):
==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000040 (READ; zero page)
#0 std::vector<grk::mj2_url>::emplace_back / push_back
#2 grk::FileFormatMJ2Decompress::read_url(...) FileFormatMJ2Decompress.cpp:351
#3 grk::FileFormatMJ2Decompress::read_dref(...) FileFormatMJ2Decompress.cpp:400
#6 grk::FileFormatJP2Family::readHeaderProcedure() FileFormatJP2Family.cpp:381
Address 0x40 = the offset of url_ within the null mj2_tk — a clean null-pointer dereference.
Impact
Null-pointer-dereference denial of service from a small untrusted .mj2 via the default
grk_decompress header parse (MJ2 auto-detected). No memory corruption. Local-untrusted-file.
Severity low (CVSS 4.0). Fix: null-check current_track_ in read_url/read_urn (and reject
dref outside a track). Discovered while verifying [[GROK-0003]] (same read_url function).