CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



CVE-2026-26283
6.20.01%

The Eternal JPEG: Infinite Loops in ImageMagick's Optimization Logic

Amit Schendel
Amit Schendel
Senior Security Researcher

Feb 24, 2026·5 min read·6 visits

No Known Exploit

Executive Summary (TL;DR)

ImageMagick has a feature to limit JPEG file size by brute-forcing quality settings. A logic error meant that if the encoder hiccuped (returned false), the loop would retry without changing parameters—forever. Update to 7.1.2-15 or 6.9.13-40 immediately.

A critical Denial of Service (DoS) vulnerability in ImageMagick's JPEG encoder allows attackers to trigger an infinite loop by abusing the `jpeg:extent` feature. By forcing a write failure during the file-size optimization process, the application enters a CPU-exhausting cycle that hangs the process indefinitely.

The Hook: Brute-Forcing Perfection

ImageMagick is the duct tape of the internet. If you upload a profile picture to a website, chances are some backend script is piping it through magick before it hits an S3 bucket. One of its handier, albeit computationally expensive, features is the jpeg:extent define.

This feature allows a user to say, "I don't care about the quality, just make sure this JPEG is under 50KB." Since JPEG compression isn't linear, ImageMagick can't just calculate the perfect quality setting mathematically. Instead, it does what computers do best: it guesses.

It implements a binary search, repeatedly encoding the image at different quality levels (0-100) until it finds the highest quality that fits within the target file size. It’s a brute-force optimization loop running inside your image processor. And as we know, loops are where the demons live.

The Flaw: The Definition of Insanity

A robust binary search needs three things: a lower bound, an upper bound, and a way to exit. In coders/jpeg.c, ImageMagick sets up this search loop to iterate through quality settings. Inside the loop, it calls WriteJPEGImage to generate a candidate image, checks its size, and adjusts the bounds accordingly.

But what happens if WriteJPEGImage fails? Not because the image is too big, but because of a resource error, an I/O glitch, or a library hiccup? The function returns MagickFalse.

The developers handled this error condition with a single instruction: continue.

Here lies the logic bomb. In a for loop, continue jumps to the increment step. But this was a while loop logic where the bounds (minimum/maximum quality) were only updated after a successful write. By hitting continue, the code skipped the logic that changes the loop state. It essentially said: "That failed. Let's try the exact same thing, with the exact same parameters, again."

It is the literal definition of insanity: doing the same thing over and over and expecting a different result. The process spins at 100% CPU, trying to encode a ghost image until the heat death of the universe or a sysadmin kill -9s it.

The Code: One Word is All It Takes

Let's look at the "smoking gun" in coders/jpeg.c. This is a classic example of how a single control flow statement can sink a battleship.

Vulnerable Logic (Simplified):

/* coders/jpeg.c before patch */
while (minimum <= maximum) {
    // ... setup logic ...
    status = WriteJPEGImage(extent_info, jpeg_image, exception);
    
    if (status == MagickFalse)
        continue;  // <--- THE KILLER. Re-loops without changing state.
    
    // The code below is unreachable if status is false
    if (GetBlobSize(jpeg_image) <= extent)
        minimum = jpeg_image->quality + 1;
    else
        maximum = jpeg_image->quality - 1;
}

The fix was embarrassingly simple. If the write fails, stop trying to optimize. Abort the loop.

The Fix:

- if (status == MagickFalse)
-   continue;
+ if (status == MagickFalse)
+   break;

By changing continue to break, the loop terminates upon failure, returning control (and the error) to the caller rather than entering an infinite spin cycle.

The Exploit: Spinning the Hamster Wheel

To weaponize this, an attacker needs two ingredients: access to pass the jpeg:extent parameter (often exposed in resizing APIs) and a way to make WriteJPEGImage fail consistently inside that loop.

WriteJPEGImage can fail for various reasons:

  1. Resource Exhaustion: If the system is near its file descriptor limit or memory limit, the internal write might fail.
  2. Filesystem Quirks: If the temporary directory used by ImageMagick is full or read-only.
  3. Corrupt Input: A crafted image that decodes successfully enough to enter the loop but contains specific pixel data that trips up the encoder at a specific step without crashing the whole process.

An attacker targeting a web service that uses ImageMagick (e.g., convert input.jpg -define jpeg:extent=50kb output.jpg) could try to flood the service with requests. If they can trigger a condition where the temporary file creation inside the loop fails, the service enters a zombie state. Send enough of these, and you starve the server's CPU cores one by one until the load average hits the stratosphere.

The Impact: The Silent Server Killer

This is a pure Availability vulnerability. There is no Remote Code Execution (RCE) here, and you aren't stealing database credentials. However, in the world of cloud computing, CPU cycles equal money, and availability equals trust.

A single malicious request can permanently peg a CPU core. If your server processes images on 4 cores, it only takes 4 requests to completely lock up the service. Because the loop is tight (CPU-bound), it doesn't wait for I/O, meaning it generates maximum heat and maximum lag.

For auto-scaling cloud groups, this is particularly nasty. The high CPU usage might trigger your auto-scaler to spin up more instances. The attacker continues to send requests, locking those up too. Essentially, this vulnerability allows an attacker to financially DoS you by forcing you to pay for a fleet of servers doing absolutely nothing but failing to compress a JPEG.

The Mitigation: Break the Cycle

The remediation is straightforward: update your libraries. The patch exists in ImageMagick 7.1.2-15 and 6.9.13-40. If you are using .NET, pull the latest Magick.NET (14.10.3).

If you cannot patch immediately, you must sanitize your inputs. If your application allows users to pass arbitrary arguments to ImageMagick (which is a terrible idea for many other reasons), block the jpeg:extent define.

Detection: Monitor your infrastructure for processes named magick or convert that have high CPU time but aren't exiting. A process running for 5+ minutes at 99% CPU is a strong indicator that you've hit this loop.

Official Patches

ImageMagickCommit fixing the infinite loop

Fix Analysis (1)

Technical Appendix

CVSS Score
6.2/ 10
CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
EPSS Probability
0.01%
Top 98% most exploited

Affected Systems

ImageMagick 7.x < 7.1.2-15ImageMagick 6.x < 6.9.13-40Magick.NET < 14.10.3

Affected Versions Detail

Product
Affected Versions
Fixed Version
ImageMagick
ImageMagick
< 7.1.2-157.1.2-15
ImageMagick (Legacy)
ImageMagick
< 6.9.13-406.9.13-40
Magick.NET
dlemstra
< 14.10.314.10.3
AttributeDetail
CWE IDCWE-835
Attack VectorLocal / Context-Dependent
CVSS Score6.2
ImpactHigh (Availability)
Exploit StatusPoC Pending
Patch Date2026-02-13

MITRE ATT&CK Mapping

T1499.004Endpoint Denial of Service: Application Exhaustion
Impact
CWE-835
Infinite Loop

Loop with Unreachable Exit Condition ('Infinite Loop')

Vulnerability Timeline

Fix committed to master branch
2026-02-13
GHSA-gwr3-x37h-h84v published
2026-02-24
CVE-2026-26283 assigned
2026-02-24

References & Sources

  • [1]GitHub Security Advisory
  • [2]CWE-835: Infinite Loop

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.