In this episode we lock down ImageMagick with security policy: limiting resources with limits, disabling dangerous coders, using the MAGICK environment variables, applying a format whitelist, and auditing behavior with logs. All to ensure your image pipeline doesn't become an attacker's entry point.

In episode 12 you saw ImageMagick as a bridge to hundreds of formats through delegates. That power has a dark side: every delegate is an attack surface. The more formats that can be processed, the more third-party code runs with your process's privileges.
Episode 13 flips the perspective. If earlier episodes asked "what can ImageMagick do?", this episode asks "what may it do?". The answer is governed by a single file called policy.xml — plus the MAGICK_* environment variables that can change behavior without touching a file. This isn't empty security theory: it's a mandatory step before your image pipeline reaches production.
policy.xml is an XML file that is the control center for all of ImageMagick's behavior — applying to the command line, and also to the libraries used by other applications that link ImageMagick. Because it's read at the process level, its policies can't be bypassed from the command line. That's what makes it a legitimate security tool, not just configuration.
The file is usually in ImageMagick's configuration directory (find it with magick -debug configure info), and its basic format is a list of policy elements with domain, name, and rights attributes:
<policymap>
<policy domain="resource" name="memory" value="256MiB"/>
<policy domain="resource" name="disk" value="1GiB"/>
<policy domain="resource" name="threads" value="2"/>
<policy domain="resource" name="width" value="8192"/>
<policy domain="resource" name="height" value="8192"/>
</policymap>Each element reads like a sentence: "in the resource domain, for the memory aspect, the maximum value is 256MiB". Policies are global and default to strict — things not mentioned in policy.xml use ImageMagick's built-in defaults, and some distributions (like Debian) even lock down many coders from installation.
Tip
The exact location of policy.xml differs between distributions and versions. Don't memorize the path — run magick -debug configure info | grep -i policy to find out which file is actually read, then make sure your policies are in that file.
The resource domain governs how much "breathing room" ImageMagick is allowed. ImageMagick's defaults are quite generous — and generous is dangerous when the input can't be trusted. Four limits changed most often:
memory — how much RAM for the image cache. Exceeding the limit makes ImageMagick move to disk.disk — how much disk space for temporary files. This is the last line of defense: without a limit, large images can flood the filesystem.threads — how many parallel threads. Limiting concurrency reduces CPU load on machines shared by many services.width/height — the maximum image dimensions. This prevents pixel-bomb images (e.g., 100,000 x 100,000) from consuming resources endlessly.The maximum dimensions are the most often overlooked and most valuable guard. A small PNG file can declare a giant size in its header; without width and height, your process will try to allocate memory according to that claim. With these limits, a bogus claim is rejected before work begins.
<policy domain="resource" name="time" value="120"/>
<policy domain="resource" name="map" value="512MiB"/>
<policy domain="resource" name="area" value="256MB"/>Besides the limits above, time limits execution seconds and map/area govern memory mapping. For services processing unknown input, the combination of memory + disk + time + width/height are the four pillars that must be present.
The coder domain controls which formats may be read. The strictest form is a whitelist: only the formats genuinely needed are allowed, everything else is rejected.
<policy domain="coder" rights="none" pattern="*"/>
<policy domain="coder" rights="read|write" pattern="PNG"/>
<policy domain="coder" rights="read|write" pattern="JPEG"/>
<policy domain="coder" rights="read|write" pattern="WEBP"/>
<policy domain="coder" rights="read|write" pattern="PDF"/>Read it as: "no format is allowed, except the ones listed". The first line closes everything, the following lines open only PNG, JPEG, WEBP, and PDF. This is the safest pattern — the inverse semantics of a blacklist, which is always outdated because new formats keep appearing.
Coders that are almost always disabled in production environments: MVG, MSL, URL, EPHEMERAL, and HTTPS. You'll see the full reasons in episode 14 — for now, just know that those coders are designed to do more than decode images, and that "more" is what's dangerous.
Two other domains that tighten security:
module — disables dynamic module loading. When on, ImageMagick could load .so libraries from unexpected locations; turning it off ensures only compiled-in modules run.path — locks down where files may be read/written. With a @/var/media/* pattern, you can ensure the pipeline only touches allowed directories, not the whole filesystem.<policy domain="module" rights="none" pattern="{PS,PDF,XPS}"/>
<policy domain="path" rights="read" pattern="@/var/media/*"/>
<policy domain="path" rights="write" pattern="@/var/out/*"/>Note the @ syntax in the path domain — the prefix marking a path pattern. Restricting path is very effective in multi-tenant environments, where one ImageMagick process serves input from many users.
Besides policy.xml, ImageMagick reads many environment variables prefixed with MAGICK_ that change runtime behavior. The two most useful for security and debugging:
export MAGICK_THREAD_LIMIT=2
export MAGICK_MEMORY_LIMIT=256MiB
export MAGICK_TIME_LIMIT=120
export MAGICK_CONFIGURE_PATH=/etc/im-configMAGICK_MEMORY_LIMIT, MAGICK_THREAD_LIMIT, and MAGICK_TIME_LIMIT are shortcuts to the resource domain without editing XML — perfect for adjusting per-service limits in containers or systemd units. MAGICK_CONFIGURE_PATH (from episode 12) points to the custom configuration directory.
The relationship between the two matters: policy.xml is global and binding, environment variables are per-process and can be looser than the policy — but can never loosen beyond the policy limits. This is a healthy composition: policy as the security floor, environment as granular adjustment above it.
Important
The limits in policy.xml are a hard ceiling. MAGICK_* and the -limit option can lower limits, but can't raise them beyond what the policy allows. This design ensures a single unruly script can't disable a machine's policy just by changing the environment.
Beyond global policy, ImageMagick has the -limit option for setting limits on a single command:
magick input.jpg -limit memory 128MiB -limit disk 256MiB -resize 50% output.jpgThe -limit memory and -limit disk above bind a single invocation only. Use this when you know one particular task is more resource-hungry than normal — for example processing high-resolution photos one by one at night — without changing the global policy for everyone.
The reason whitelists are preferred over blacklists is the future problem. A blacklist lists formats that are dangerous now; a format born next month isn't on the list, so it's safe by accident. A whitelist lists formats that are intentionally allowed; anything born outside the list is rejected from birth.
Analogize with building security: a blacklist is the list of names that may not enter, a whitelist is the list of names that may enter. The first list requires you to know all future criminals; the second list just requires you to know the invited guests. For production pipelines, the right answer is always the whitelist.
A policy without observation is useless. ImageMagick can write detailed logs about what it's doing — when, in which file, how much resource was used:
magick -log events=All -log format='%t %d %[filename]' \
-limit memory 128MiB input.jpg output.pngThe log format above records the time, event domain, and file name being processed. On servers processing user uploads, this log stream is an audit trail: you can see when suspicious input arrived, how long it was processed, and where it stopped.
For truly supervised environments, route the log to syslog or a centralized file, then set up alerts when error messages like cache resources exhausted or no decode delegate appear repeatedly. Those patterns are usually not accidents — they're failed attempts.
Warning
Never treat logs as a substitute for limits. Logs tell you after something happens; policy.xml prevents it before. Install both, and direct them to two different places — logs stored only on the same machine can disappear along with the machine.
Episode 13 turned ImageMagick from an all-capable tool into a tool that knows its limits: limiting resources with the resource domain and -limit, closing dangerous coders with the coder domain, applying a format whitelist that never needs updating, locking down module and path execution, changing per-process behavior with the MAGICK_* environment variables, and watching everything with -log.
The core thing to remember: security policy is design, not patching. Format whitelists and resource limits aren't secondary features — they're the line of defense that determines whether your image pipeline can handle input from the outside world without collapsing.
In episode 14 we look at the most concrete reason why all these policies are mandatory: ImageTragick — the RCE vulnerability that shook the ImageMagick world in 2016, and the survival lessons born from it. See you then!