Feb 24, 2026·6 min read·8 visits
A memory leak in ImageMagick's MSL component allows attackers to crash servers via DoS. By sending requests that trigger the `WriteMSLImage` function, the server allocates memory for a cloned image but never frees it. Fix involves patching to 7.1.2-15+ or disabling MSL in policy.xml.
ImageMagick, the ubiquitous Swiss Army knife of image processing, has stumbled again—not with a high-profile Remote Code Execution (RCE) this time, but with a silent killer: a memory leak in the Magick Scripting Language (MSL) encoder. CVE-2026-25638 allows unauthenticated attackers to exhaust server memory by triggering the `WriteMSLImage` function, leading to a Denial of Service (DoS). While less glamorous than shell access, this vulnerability highlights the dangers of legacy components and improper resource management in C.
ImageMagick is the software equivalent of a hoarder's garage. It keeps everything. Did you know ImageMagick has its own XML-based scripting language called MSL (Magick Scripting Language)? Neither did half the developers using it. But in the world of vulnerability research, obscure features are where the bodies are buried.
CVE-2026-25638 targets this specific corner of the codebase: the coders/msl.c module. This component is responsible for interpreting and writing MSL scripts. While modern web applications typically interact with ImageMagick via libraries or CLI wrappers to convert JPEGs to PNGs, the internal machinery still loads these obscure coders if not explicitly forbidden.
This vulnerability isn't the flashy "ImageTragick" RCE that keeps CISOs up at night. It's something more insidious. It's a resource exhaustion bug—a memory leak. It’s the equivalent of opening a new tab in Chrome every time a user visits your site, but never closing it. Eventually, the machine stops responding. For high-throughput image processing pipelines (like those used by social media platforms or e-commerce sites), this is a production-halting nightmare waiting to happen.
To understand this bug, we have to look at how ImageMagick handles image transformations internally. When the MSL writer is invoked, it needs to perform operations on an image without destroying the original data immediately. To do this, it creates a clone.
In coders/msl.c, the function WriteMSLImage is called. Its job is to take the current image state and process it according to the MSL script provided. The developers correctly identified that they shouldn't modify the input image directly in case the operation failed or needed to be non-destructive initially. So, they called CloneImage.
Here is where the logic falls apart. In C, there is no garbage collector to sweep up after you. If you malloc (or in this case, CloneImage), you must free (or DestroyImageList). The vulnerable code allocates a potentially large structure on the heap to hold the msl_image, passes it to the processing function, and then... just walks away. The function returns the status code, leaving the cloned image stranded in memory. It is an orphan object, occupying RAM, with no pointer left to free it.
Let's look at the diff. It is painfully simple, which is characteristic of the most annoying bugs to debug. The fix introduced in commit 1e88fca11c7b8517100d518bc99bd8c474f02f88 adds exactly one line of cleanup code.
Here is the vulnerable flow in coders/msl.c:
/* Vulnerable Code */
static MagickBooleanType WriteMSLImage(const ImageInfo *image_info, Image *image,
ExceptionInfo *exception)
{
Image *msl_image;
MagickBooleanType status;
/* ... setup code ... */
/* 1. ALLOCATION: Create a deep copy of the image */
msl_image = CloneImage(image, 0, 0, MagickTrue, exception);
/* 2. USE: Process the script using the clone */
status = ProcessMSLScript(image_info, &msl_image, exception);
/* 3. RETURN: The function exits, leaking msl_image! */
return(status);
}The fix is the digital equivalent of remembering to turn off the stove:
msl_image=CloneImage(image,0,0,MagickTrue,exception);
status=ProcessMSLScript(image_info,&msl_image,exception);
+ msl_image=DestroyImageList(msl_image);
return(status);Without that DestroyImageList call, every single request that hits this code path leaks the size of the image structure plus its pixel cache. If you send a 4K image to be processed by MSL, you aren't just leaking a few bytes; you could be leaking dozens of megabytes per request.
How do we weaponize a memory leak? We don't need complex shellcode or ROP chains. We just need persistence and volume. The goal is the OOM (Out of Memory) Killer.
The attacker needs to force the server to invoke the MSL coder. If the application allows users to upload files and automatically detects the format based on magic bytes or file extension, the attacker can upload a file named payload.msl or simply an XML file with MSL headers.
/api/convert or /profile/upload that uses ImageMagick.<?xml version="1.0" encoding="UTF-8"?>
<image>
<read filename="image.jpg" />
<resize geometry="100x100" />
<write filename="output.png" />
</image>WriteMSLImage is called 50 times a second. Each call clones image.jpg. The heap grows. The garbage collector (if the app wrapper has one) can't help because the leak is inside the C library, outside the managed runtime's view.magick worker. The service goes dark.There are two ways to fix this. One is surgical, the other is architectural.
Obviously, update ImageMagick. The fix is available in versions 7.1.2-15 and 6.9.13-40. This patches the specific leak in coders/msl.c. If you are compiling from source, ensure you have commit 1e88fca applied.
This is the "Hacker's Choice" for defense. Why does your web server even know how to process MSL scripts? The principle of least privilege applies to code, too. ImageMagick's policy.xml is a powerful firewall for format parsers.
You should explicitly disable the MSL coder (and any others you don't use, like MVG, XPS, or PDF) to reduce your attack surface.
<policymap>
<!-- Disable MSL completely -->
<policy domain="coder" rights="none" pattern="MSL" />
<!-- While you're at it, disable these usually dangerous ones too -->
<policy domain="coder" rights="none" pattern="MVG" />
<policy domain="coder" rights="none" pattern="HTTPS" />
</policymap>By adding this policy, even if the binary is vulnerable, the exploit fails at step 1 because ImageMagick will refuse to load the MSL module entirely.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L| Product | Affected Versions | Fixed Version |
|---|---|---|
ImageMagick ImageMagick | >= 7.0.0, < 7.1.2-15 | 7.1.2-15 |
ImageMagick ImageMagick | < 6.9.13-40 | 6.9.13-40 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-401 (Missing Release of Memory) |
| CVSS v3.1 | 5.3 (Medium) |
| Attack Vector | Network (AV:N) |
| Impact | Denial of Service (Availability) |
| Component | coders/msl.c (WriteMSLImage) |
| Exploit Maturity | Proof of Concept |
Missing Release of Memory after Effective Lifetime