PUBLIC MIRROR A read-only public view of Anvil. Only publicly-disclosed findings are shown; the Playbook, techniques, sessions and embargoed research are hidden.

← Findings

GROK-0013

low harness-verified

MJ2 read_url/read_urn: NULL-pointer dereference of current_track_ when a dref/url box has no preceding tkhd

Harness reproduced Crashes in a custom/AI-generated harness under a sanitizer. A TEST ARTIFACT — not real-world verification.

⚠ Harness reproduced — not real-world verified. Reproduce through the public API, a real application, or a platform decoder before treating this as verified.

Crash SEGV / NULL-pointer dereference
Topmost entry point unknown — establish reachability
Verified through no real consumer named
Real-world impact 4 CVSS · low

Classification

TargetGrok
ComponentJP2 file format
Locationsrc/lib/core/fileformat/decompress/FileFormatMJ2Decompress.cpp · read_url / read_urn:351,377
Vuln classdos
CVE
CVSS4 (CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H)
Discovered2026-06-16

Verification

Evidence Harness reproduced (not real-world verified)
Harness fired✅ yes
Protocol1.0
Sanitizerasan
Crash typeSEGV / NULL-pointer dereference
Reproclang-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 toGrok maintainers — support@grokcompression.com (private email; repo has no Private Vulnerability Reporting / SECURITY.md)
Reported2026-06-23
Vendor ack
Embargo until
Public2026-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 drefurl 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).

References