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



GHSA-QP59-X883-77QV
6.5

Magick Leaks: Drowning in OpenCL Benchmarks

Amit Schendel
Amit Schendel
Senior Security Researcher

Feb 16, 2026·5 min read·11 visits

PoC Available

Executive Summary (TL;DR)

ImageMagick's OpenCL device profiler leaks memory when parsing bad XML. By placing a malformed 'ImagemagickOpenCLDeviceProfile.xml' in the cache directory, an attacker can cause persistent memory leaks in long-running processes, eventually leading to Denial of Service.

A memory leak vulnerability exists in ImageMagick's OpenCL benchmarking component. When parsing malformed device profile XML files, the parser fails to release allocated string members within the benchmark structure, leading to resource exhaustion.

The Hook: Speed at Any Cost

ImageMagick is the heavy lifter of the internet. If you've ever uploaded a photo to a website and it magically resized itself, ImageMagick probably did the work. To keep up with the demand for speed, the library tries to offload work to your GPU using OpenCL. But GPUs are finicky beasts, so ImageMagick runs a "benchmark" the first time it sees a device to figure out if it's worthy of the workload.

This benchmark data is cached in an XML file so it doesn't have to run every time. It sounds efficient, right? Well, that caching mechanism is where our story begins. In the rush to parse this XML and get to the GPU acceleration, the developers left a small but critical gap in their memory management logic. It’s a classic case of "happy path" programming—assuming the data is always good, and failing to clean up the mess when it isn't.

This isn't a remote code execution that will give you a shell in five seconds. It's a slow burn. A memory leak. It's the digital equivalent of a dripping faucet that eventually floods the basement. In long-running services that process thousands of images, this drip turns into a deluge.

The Flaw: An Orphaned Allocation

The vulnerability lives in MagickCore/opencl.c, specifically within the LoadOpenCLDeviceBenchmark() function. This function is tasked with reading ImagemagickOpenCLDeviceProfile.xml. It iterates through the XML nodes, looking for <device> tags. When it finds one, it does what any good C program does: it asks the operating system for some memory.

It allocates a MagickCLDeviceBenchmark structure. Inside that structure, there are pointers to strings: platform_name, vendor_name, name, and version. These aren't just fixed buffers; they are dynamically allocated strings created via ConstantString().

Here is the logic flaw: The code assumes that if the XML parsing fails or hits a weird state (like a malformed tag), it should just free the parent structure (device_benchmark) and bail out. The problem is that freeing a struct in C does not free the pointers inside it. It's like demolishing a house but leaving all the furniture floating in mid-air. The parent container is gone, but the string allocations remain in the heap, orphaned and unreachable.

The Code: Explicit vs. Implicit Cleanup

Let's look at the crime scene. In the vulnerable version of MagickCore/opencl.c, the cleanup block at the end of the function (or during error handling) looked something like this:

// The Vulnerable Exit Block
 
// 1. Free the temporary token string
token=(char *) RelinquishMagickMemory(token);
 
// 2. Free the benchmark struct itself
device_benchmark=(MagickCLDeviceBenchmark *) 
  RelinquishMagickMemory(device_benchmark);  
 
// WAIT! What about device_benchmark->platform_name?
// What about device_benchmark->vendor_name?
// They are gone. Leaked forever.

The fix is straightforward but tedious. You have to manually walk through the struct and free every member before you free the struct itself. This is why languages like Rust are eating C's lunch, but I digress. Here is the corrected logic:

// The Fixed Cleanup Logic
 
if (device_benchmark != (MagickCLDeviceBenchmark *) NULL)
{
  // Manually free every string member first
  if (device_benchmark->platform_name != (char *) NULL)
    device_benchmark->platform_name=
      RelinquishMagickMemory(device_benchmark->platform_name);
      
  if (device_benchmark->vendor_name != (char *) NULL)
    device_benchmark->vendor_name=
      RelinquishMagickMemory(device_benchmark->vendor_name);
      
  // ... repeat for name and version ...
 
  // Finally, free the parent struct
  device_benchmark=(MagickCLDeviceBenchmark *) 
    RelinquishMagickMemory(device_benchmark);
}

The Exploit: Poisoning the Cache

To exploit this, we don't need to overflow a buffer; we just need to lie to the parser. The parser expects a well-formed XML entry like <device name="..." />. If we give it a <device tag that opens but never closes, or contains garbage, the parser hits the error path—the same error path that forgets to free memory.

The attack vector is local, which limits the fun, but it's deadly in shared environments. The target file is typically located at ~/.cache/ImageMagick/ImagemagickOpenCLDeviceProfile.xml. If you are on a multi-user system or a web server where you can write files to the working directory or the user's home (perhaps via a separate unrestricted file upload vulnerability), you can drop this time bomb.

The Payload:

<managed_devices>
  <!-- Open the tag, allocate the memory, but never close it -->
  <device 
    platform="LeakyPlatformString_That_Takes_Up_Space" 
    vendor="LeakyVendorString_That_Takes_Up_Space" 
    name="LeakyName_That_Takes_Up_Space" 
    version="1.0" 

Every time the ImageMagick library initializes (which could be every time a PHP script processes an upload), it reads this file. It allocates the strings. It hits the malformed syntax. It errors out. It leaks the strings. Rinse and repeat until the server runs out of RAM and the OOM killer steps in.

The Fix: Better Housekeeping

The remediation is simple: update. The Magick.NET team (specifically dlemstra) identified this and patched it in version 14.10.2. For the core C library, you'll want to be on 7.1.2-13 or later.

If you can't update immediately, you have two options. First, verify permissions on the ImageMagick cache directory. Ensure that the user running the ImageMagick process is the only one who can write to it. If an attacker can't place the XML file, they can't trigger the leak.

Second, turn off the feature entirely. If you aren't doing heavy lifting that requires OpenCL (and let's be honest, most simple web resizing tasks don't), you can disable it via environment variables or the policy.xml configuration. No OpenCL means no benchmarking, which means no XML parsing, which means no leak.

Official Patches

Magick.NETMagick.NET Release 14.10.2 containing the fix

Technical Appendix

CVSS Score
6.5/ 10
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:L/A:H

Affected Systems

ImageMagick <= 7.1.2-12Magick.NET < 14.10.2Magick.NET-Q8Magick.NET-Q16Magick.NET-Q16-HDRI

Affected Versions Detail

Product
Affected Versions
Fixed Version
ImageMagick
ImageMagick Studio LLC
<= 7.1.2-127.1.2-13
Magick.NET
dlemstra
< 14.10.214.10.2
AttributeDetail
CWECWE-401 (Memory Leak)
Attack VectorLocal (File System)
CVSS6.5 (Medium)
ComponentMagickCore/opencl.c
FunctionLoadOpenCLDeviceBenchmark
Exploit StatusProof of Concept Available

MITRE ATT&CK Mapping

T1499Endpoint Denial of Service
Impact
T1499.004Endpoint Denial of Service: Application or System Exploitation
Impact
CWE-401
Missing Release of Memory after Effective Lifetime

The software does not sufficiently track and release allocated memory after it has been used, which effectively reduces available memory over time.

Known Exploits & Detection

GitHub AdvisoryAdvisory and analysis by dlemstra detailing the memory leak in opencl.c

Vulnerability Timeline

Vulnerability Published (GHSA)
2026-01-21
Advisory Modified
2026-02-03

References & Sources

  • [1]ImageMagick Source Code
  • [2]Magick.NET Wrapper

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.