ANT-2026-GPA6MCZ6 · libvips/libvips

heap-buffer-overflow high

Severity Claude high · Security research firm high · Maintainer -

Discovered by Claude Sonnet 4.6

REPORT

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

ANT-2026-GPA6MCZ6: Heap-buffer-overflow in region.c:1614

In libvips's SIMD-accelerated horizontal reduce (reduceh_hwy.cpp:213), the AVX2 code path issues a LoadU that reads 8 bytes starting 4 bytes beyond a 52-byte heap allocation. The overflow is reached through vips_reduceh_uchar_vector_gen during normal region generation, i.e. the standard resize pipeline. An attacker who can submit an image with dimensions/bands that exercise this tail case can trigger the over-read. The result is a process crash (DoS) and potentially leaking a few adjacent heap bytes into output pixel data.

Target

Project: libvips
Location: region.c:1614

Technical Details

ASAN: "READ of size 8 at 0x745be5fe1d38 ... located 4 bytes after 52-byte region". The vectorized inner loop in vips_reduceh_uchar_hwy calls hwy LoadU without ensuring the remaining source bytes cover the full vector width, so for certain input widths/band counts the final load runs off the end of the source scanline buffer.

Crash trace (truncated — full trace in attached crash.log):

INFO: Running with entropic power schedule (0xFF, 100).
INFO: Seed: 2784531891
INFO: Loaded 1 modules   (302682 inline 8-bit counters): 302682 [0x60abdeb2ae28, 0x60abdeb74c82), 
INFO: Loaded 1 PC tables (302682 PCs): 302682 [0x60abdeb74c88,0x60abdf013228), 
/out/vips_fuzzer: Running 1 inputs 1 time(s) each.
Running: /tmp/poc
EXIT_CODE:1


=== ASAN Report ===
=================================================================
==27==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x745be5fe1d38 at pc 0x60abdba54132 bp 0x73fbe159e170 sp 0x73fbe159e168
READ of size 8 at 0x745be5fe1d38 thread T2
    #0 0x60abdba54131 in Load<hwy::N_AVX2::Simd<unsigned char, 32UL, -2>, nullptr, nullptr> /work/include/hwy/ops/x86_128-inl.h:2214:21
    #1 0x60abdba54131 in LoadU<hwy::N_AVX2::Simd<unsigned char, 32UL, -2>, nullptr> /work/include/hwy/ops/x86_128-inl.h:2275:10
    #2 0x60abdba54131 in N_AVX2::vips_reduceh_uchar_hwy(unsigned char*, unsigned char*, int, int, int, short* restrict*, double, double) /src/libvips/build/../libvips/resample/reduceh_hwy.cpp:213:18
    #3 0x60abdba4f845 in vips_reduceh_uchar_vector_gen(_VipsRegion*, void*, void*, void*, int*) /src/libvips/build/../libvips/resample/reduceh.cpp:380:3
    #4 0x60abdb8baf16 in vips_region_generate /src/libvips/build/../libvips/iofuncs/region.c:1614:6
    #5 0x60abdb8a8626 in vips_region_fill /src/libvips/build/../libvips/iofuncs/region.c:867:7
    #6 0x60abdb8baad6 in vips_region_prepare /src/libvips/build/../libvips/iofuncs/region.c:1682:7
    #7 0x60abdbabeab6 in vips_copy_gen /src/libvips/build/../libvips/conversion/copy.c:140:6
    [... 52 more frames — full trace in crash.log]

Reproduction

  1. Craft an input whose width/bands produce a source scanline length that leaves a short tail for the SIMD loop
  2. Invoke a libvips resize/reduceh on the image (e.g. thumbnail endpoint)
  3. vips_reduceh_uchar_hwy executes LoadU past the end of the source buffer, triggering the OOB read

[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-GPA6MCZ6.


Reference: ANT-2026-GPA6MCZ6
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/ChangeLog b/ChangeLog
index 91a9afd6e6..2967eed3a4 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -20,6 +20,7 @@ tbd 8.18.3
 - source: fix max/min confusion [Himanshu Anand]
 - uhdrsave: use macro to size buffer [Himanshu Anand]
 - draw_mask: fix support for packed LABQ images [lovell]
+- reduceh: fix possible OOB read in Highway path [kleisauke]
 
 31/3/26 8.18.2
 
diff --git a/libvips/resample/reduceh.cpp b/libvips/resample/reduceh.cpp
index bc35d472e0..ec5a89832f 100644
--- a/libvips/resample/reduceh.cpp
+++ b/libvips/resample/reduceh.cpp
@@ -356,7 +356,10 @@ vips_reduceh_uchar_vector_gen(VipsRegion *out_region, void *seq,
 
 	s.left = r->left * reduceh->residual_hshrink - reduceh->hoffset;
 	s.top = r->top;
-	s.width = r->width * reduceh->residual_hshrink + reduceh->n_point;
+	/* Request one extra input pixel on the right so the Highway path can
+	 * safely process a full SIMD vector.
+	 */
+	s.width = (r->width + 1) * reduceh->residual_hshrink + reduceh->n_point;
 	s.height = r->height;
 	if (vips_region_prepare(ir, &s))
 		return -1;
diff --git a/test/test-suite/test_resample.py b/test/test-suite/test_resample.py
index 63c95c828a..00d4eb8358 100644
--- a/test/test-suite/test_resample.py
+++ b/test/test-suite/test_resample.py
@@ -102,6 +102,14 @@ def test_reduce(self):
                 d = abs(shr.avg() - im.avg())
                 assert d == 0
 
+        # https://github.com/libvips/libvips/issues/4864
+        if have("ppmload"):
+            im = pyvips.Image.new_from_buffer(b'P6\n2 2\n255\n'
+                                              b'\xff\x00\x00' b'\x00\xff\x00'
+                                              b'\x00\x00\xff' b'\xff\xff\x00', "")
+            im2 = im.reduceh(1.5, kernel="nearest")
+            assert im2.width == 1
+
     def test_resize(self):
         im = pyvips.Image.new_from_file(JPEG_FILE)
         im2 = im.resize(0.25)

https://github.com/libvips/libvips/commit/aebac9b8593956bffbd1bcacc52d8acf7219815e

TIMELINE

Dates from discovery through public reveal.

  1. 2026-03-24 Reported to tracker
  2. 2026-05-13 Sent to maintainer
  3. 2026-05-13 Maintainer acknowledged
  4. 2026-06-09 Patch released
  5. 2026-08-17 Publicly revealed
PROVENANCE

SHA-3-512 hash:

c81718c6db39bdeaef9dc0718ca1c609b3c60bfdca59ce026527591433b950b0f6765ce4ce87eb0086cee48d5f1100df583cc2c8369a006f541e6482936143b6

Committed 2026-05-13 10:56 PT

Revealed 2026-08-17 10:47 PT

Verify (download preimage.json)

Show preimage JSON
{
  "ant_id": "ANT-2026-GPA6MCZ6",
  "bug_class": "Heap-buffer-overflow",
  "claude_severity": "high",
  "commit_sha": null,
  "created_at": "2026-03-24T18:33:33+00:00",
  "description": "In libvips's SIMD-accelerated horizontal reduce (reduceh_hwy.cpp:213), the AVX2 code path issues a LoadU that reads 8 bytes starting 4 bytes beyond a 52-byte heap allocation. The overflow is reached through vips_reduceh_uchar_vector_gen during normal region generation, i.e. the standard resize pipeline. An attacker who can submit an image with dimensions/bands that exercise this tail case can trigger the over-read. The result is a process crash (DoS) and potentially leaking a few adjacent heap bytes into output pixel data.",
  "discovered_at": null,
  "location": "region.c:1614",
  "poc_sha256": null,
  "preimage_version": 1,
  "project": "libvips",
  "reproduction": [
    "1. Craft an input whose width/bands produce a source scanline length that leaves a short tail for the SIMD loop",
    "2. Invoke a libvips resize/reduceh on the image (e.g. thumbnail endpoint)",
    "3. vips_reduceh_uchar_hwy executes LoadU past the end of the source buffer, triggering the OOB read"
  ],
  "technical_details": "ASAN: \"READ of size 8 at 0x745be5fe1d38 ... located 4 bytes after 52-byte region\". The vectorized inner loop in vips_reduceh_uchar_hwy calls hwy LoadU without ensuring the remaining source bytes cover the full vector width, so for certain input widths/band counts the final load runs off the end of the source scanline buffer.",
  "title": "Heap-buffer-overflow in region.c:1614",
  "vendor_severity": "high"
}