ANT-2026-GPA6MCZ6 · libvips/libvips
heap-buffer-overflow high
Severity Claude high · Security research firm high · Maintainer -
Discovered by Claude Sonnet 4.6
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
- Craft an input whose width/bands produce a source scanline length that leaves a short tail for the SIMD loop
- Invoke a libvips resize/reduceh on the image (e.g. thumbnail endpoint)
- 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
Triage and disclosure were performed by Ada Logics.
- Verdict
- true positive
- Severity
- high
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
Dates from discovery through public reveal.
- 2026-03-24 Reported to tracker
- 2026-05-13 Sent to maintainer
- 2026-05-13 Maintainer acknowledged
- 2026-06-09 Patch released
- 2026-08-17 Publicly revealed
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"
}