ANT-2026-K3APEMB5 · osgeo/gdal

heap-buffer-overflow high

Severity Claude critical · Security research firm high · Maintainer -

Discovered by Claude Mythos Preview

REPORT

Anthropic's analysis, sealed at approval. Disclosure to the maintainer was performed by Ada Logics.

ANT-2026-K3APEMB5: Heap-buffer-overflow in gdal

The libFuzzer harness mrf_fuzzer was executed against a single reproducer (/tmp/poc) and exited with status 1, but the log contains no AddressSanitizer/UBSan diagnostic, no crashing function, and no stack frames. Without a sanitizer tag or backtrace, the crash type, access shape (READ/WRITE, size), and source location cannot be determined from this output alone.

Target

Project: gdal

Technical Details

Fuzz target mrf_fuzzer terminated with EXIT_CODE:1 on the provided PoC; no sanitizer (ASAN/UBSan) report or stack trace was emitted.

Crash trace:

INFO: Running with entropic power schedule (0xFF, 100).
INFO: Seed: 2887737378
INFO: Loaded 1 modules   (1021859 inline 8-bit counters): 1021859 [0x638c0623a440, 0x638c06333be3), 
INFO: Loaded 1 PC tables (1021859 PCs): 1021859 [0x638c06333be8,0x638c072cb618), 
/out/mrf_fuzzer: Running 1 inputs 1 time(s) each.
Running: /tmp/poc
EXIT_CODE:1

Reproduction

Reproduce against the target as described under Technical Details.

[No reproducer or sanitizer output attached — request from security-cvd@anthropic.com if needed.]

Acknowledgement

This vulnerability was discovered by Claude, Anthropic's AI assistant, and triaged by the Anthropic security team in collaboration with Anthropic Research. Please direct questions to security-cvd@anthropic.com and reference ANT-2026-K3APEMB5.


Reference: ANT-2026-K3APEMB5
Anthropic CVD Policy: https://www.anthropic.com/coordinated-vulnerability-disclosure

SECURITY RESEARCH FIRM ANALYSIS

Triage and disclosure were performed by Ada Logics.

Verdict
true positive
Severity
high
UPSTREAM FIX

The change that resolved this finding.

diff --git a/frmts/mrf/mrf_band.cpp b/frmts/mrf/mrf_band.cpp
index d4f71a7cd041..21e6dad1b6ba 100644
--- a/frmts/mrf/mrf_band.cpp
+++ b/frmts/mrf/mrf_band.cpp
@@ -898,7 +898,16 @@ CPLErr MRFRasterBand::FetchClonedBlock(int xblk, int yblk, void *buffer)
     MRFDataset *poSrc = static_cast<MRFDataset *>(poMRFDS->GetSrcDS());
     if (nullptr == poSrc)
     {
-        CPLError(CE_Failure, CPLE_AppDefined, "MRF: Can't open source file %s",
+        CPLError(CE_Failure, CPLE_AppDefined, "MRF: Can't open source %s",
+                 poMRFDS->source.c_str());
+        return CE_Failure;
+    }
+    // Check that the source is an MRF
+    auto srcDriver = poSrc->GetDriver();
+    if (srcDriver == nullptr || !EQUAL(srcDriver->GetDescription(), "MRF"))
+    {
+        CPLError(CE_Failure, CPLE_AppDefined,
+                 "MRF: Cloned source %s is not an MRF",
                  poMRFDS->source.c_str());
         return CE_Failure;
     }
@@ -908,11 +917,35 @@ CPLErr MRFRasterBand::FetchClonedBlock(int xblk, int yblk, void *buffer)
         // Can't store, so just fetch from source, which is an MRF with
         // identical structure
         MRFRasterBand *b =
-            static_cast<MRFRasterBand *>(poSrc->GetRasterBand(nBand));
+            reinterpret_cast<MRFRasterBand *>(poSrc->GetRasterBand(nBand));
+
+        // Check the datatype and structure of the bands
+        // This is a sanity check, the source is lazy opened
+        if (b == nullptr || poSrc->GetRasterCount() != poMRFDS->nBands ||
+            poSrc->GetRasterXSize() != poMRFDS->full.size.x ||
+            poSrc->GetRasterYSize() != poMRFDS->full.size.y)
+        {
+            CPLError(CE_Failure, CPLE_AppDefined,
+                     "MRF: Cloned source %s doesn't have the same structure",
+                     poMRFDS->source.c_str());
+            return CE_Failure;
+        }
+
+        // Switch to overview if needed
         if (b->GetOverviewCount() && m_l)
             b = static_cast<MRFRasterBand *>(b->GetOverview(m_l - 1));
         if (b == nullptr)
             return CE_Failure;
+
+        // One last check, blocksize and type matches
+        int bsx, bsy;
+        b->GetBlockSize(&bsx, &bsy);
+        if (bsx != img.pagesize.x || bsy != img.pagesize.y ||
+            b->GetRasterDataType() != eDataType)
+        {
+            return CE_Failure;
+        }
+
         return b->IReadBlock(xblk, yblk, buffer);
     }
 
diff --git a/frmts/mrf/mrf_util.cpp b/frmts/mrf/mrf_util.cpp
index b2b7b2bcd5a4..75cc83618b4a 100644
--- a/frmts/mrf/mrf_util.cpp
+++ b/frmts/mrf/mrf_util.cpp
@@ -679,6 +679,10 @@ void GDALRegister_MRF()
         "optimization\n"
 #if defined(BRUNSLI)
         "       JFIF - boolean, for JPEG, disable brunsli encoding\n"
+#endif
+#if defined(QB3_SUPPORT)
+        "       QB3_BAND_MAP - space separted list of band indices for "
+        "band to band decorrelation\n"
 #endif
         "'/>"
         "</CreationOptionList>\n");

https://github.com/OSGeo/gdal/commit/e2b913be67cda104a84aa1f9449cd9479707f4d0

TIMELINE

Dates from discovery through public reveal.

  1. 2026-03-24 Reported to tracker
  2. 2026-04-29 Sent to maintainer
  3. 2026-05-08 Patch released
  4. 2026-05-12 Maintainer acknowledged
  5. 2026-07-08 Publicly revealed
PROVENANCE

SHA-3-512 hash:

7d3067339b8ed530b7bd76b9cabeae8e1570bc0e7f51294169a287f0f5686654291c6668fb791dd4748cf626bb3a2d0d0f79476c256da73a6ef7f07446d06d9c

Committed 2026-05-07 03:17 PT

Revealed 2026-07-08 16:46 PT

Verify (download preimage.json)

Show preimage JSON
{
  "ant_id": "ANT-2026-K3APEMB5",
  "bug_class": "Heap-buffer-overflow",
  "claude_severity": "critical",
  "commit_sha": null,
  "created_at": "2026-03-24T18:28:27+00:00",
  "description": "The libFuzzer harness mrf_fuzzer was executed against a single reproducer (/tmp/poc) and exited with status 1, but the log contains no AddressSanitizer/UBSan diagnostic, no crashing function, and no stack frames. Without a sanitizer tag or backtrace, the crash type, access shape (READ/WRITE, size), and source location cannot be determined from this output alone.",
  "discovered_at": null,
  "location": null,
  "poc_sha256": null,
  "preimage_version": 1,
  "project": "gdal",
  "reproduction": null,
  "technical_details": null,
  "title": "Heap-buffer-overflow in gdal",
  "vendor_severity": "high"
}