PT-2026-76319 · Julia · Imagemagick Jll
Published
2026-07-30
·
Updated
2026-07-30
CVSS v3.1
5.5
Medium
| Vector | AV:L/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H |
Summary
A single root cause in the CLAHE implementation — tile width/height becoming zero — produces two distinct but related unsafe behaviors.
Vulnerabilities exists in the
CLAHEImage() function of ImageMagick’s MagickCore/enhance.c.- Unsigned integer underflow → out-of-bounds pointer arithmetic (OOB): when
tile info.height == 0, the expressiontile info.height - 1(unsigned) wraps to a very large value; using that value in pointer arithmetic yields a huge offset and OOB memory access (leading to memory corruption, SIGSEGV, or resource exhaustion). - Division/modulus by zero: where code performs
... / tile info.widthor... % tile info.heightwithout re-checking for zero, causing immediate division-by-zero crashes under sanitizers orabortat runtime.
Both behaviors are triggered by the same invalid tile condition (e.g., CLI exact
-clahe 0x0! or automatic tile derivation dim >> 3 == 0 for very small images).Details
Unsigned underflow(can lea to OOB)
-
Location:
MagickCore/enhance.c, around line 609 -
Version tested: 7.1.2-8 (local ASan(undefined). /UBSan build)
-
Vulnerable code
enhance.c: 609
c
p += (ptrdiff t) clahe info->width * (tile.height - 1);-
Root Cause
- If
tile.height == 0, then(tile.height - 1)underflows toUINT MAX. - Multiplication with
clahe info->widthyields a huge value close toSIZE MAX. - Adding this to
pcauses pointer arithmetic underflow.
- If
Division-by-zero
-
File / Location:
MagickCore/enhance.c, around line 669 -
Version tested: 7.1.2-8 (local ASan(undefined). /UBSan build)
-
vulnerable code
enhance.c: 669-673
c
if ((image->columns % tile info.width) != 0)
tile info.x=(ssize t) (tile info.width-(image->columns % tile info.width));
tile info.y=0;
if ((image->rows % tile info.height) != 0)
tile info.y=(ssize t) (tile info.height-(image->rows % tile info.height));- Root cause
Missing input validation / bounds checks after computing default tile dimensions:
If either
tile info.width or tile info.height is 0, this triggers a division by zero. Zeros can reach this point through:- Exact tiles: CLI
clahe 0x0!(the!forces zero to be used verbatim). - Auto tiles on tiny images: When a requested tile is
0(no!), the code derives a default from the image size (e.g.,dim >> 3). For images withdim < 8, this result is 0 unless clamped.
Reproduction
Unsigned underflow
Environment
Built with AddressSanitizer and UndefinedBehaviorSanitizer enabled.
c
export UBSAN OPTIONS=print stacktrace=1:halt on error=1
export ASAN OPTIONS=abort on error=1:allocator may return null=1:detect leaks=0Command
bash
./magick xc:black -clahe 0x0 null:Output
MagickCore/enhance.c:609:6: runtime error: addition of unsigned offset overflowed
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior MagickCore/enhance.c:609:6 in CLAHEImage./magick -size 10x10 xc:black -clahe 0x0 null:Command
bash
./magick -size 16x2 gradient: -type TrueColor -depth 8 -clahe 0x0! null:Output
Suggested concrete patch snippets
Apply in
CLAHEImage() after tile info is computed but before any division/modulus/pointer arithmetic:c
if (exact tiles requested && (tile info.width == 0 || tile info.height == 0)) {
ThrowMagickException(exception, GetMagickModule(), OptionError,
"CLAHEInvalidTile", "%lux%lu",
(unsigned long) tile info.width,
(unsigned long) tile info.height);
return (Image *) NULL;
}
if (!exact tiles requested) {
tile info.width = (tile info.width == 0) ? MagickMax((size t)1, image->columns >> 3) : tile info.width;
tile info.height = (tile info.height == 0) ? MagickMax((size t)1, image->rows >> 3) : tile info.height;
}
if (tile info.width == 0 || tile info.height == 0) {
ThrowMagickException(exception, GetMagickModule(), OptionError,
"CLAHEInvalidTile", "%lux%lu",
(unsigned long) tile info.width,
(unsigned long) tile info.height);
return (Image *) NULL;
}
ssize t tile h minus1 = (ssize t)tile info.height - 1;
if (tile h minus1 < 0) {
ThrowMagickException(exception, GetMagickModule(), OptionError,
"CLAHEInvalidTile", "%lux%lu",
(unsigned long) tile info.width,
(unsigned long) tile info.height);
return (Image *) NULL;
}
p += (ptrdiff t) clahe info->width * tile h minus1;Notes about
exact tiles requested: if the CLI/Wand parser already exposes whether ! was present, use it. If not, add a parse-time flag so CLAHEImage can know whether 0 is literal or auto.Credit
Team Whys
Bug Hunting Master Program, HSpace/Findthegap
Youngmin Kim
kunshim@naver.com
Woojin Park
Youngin Won
Siyeon Han
Shinyoung Won
Fix
Found an issue in the description? Have something to add? Feel free to write us 👾
Related Identifiers
Affected Products
Imagemagick Jll