This is a sample engagement report, built on my own open tool, Image Payload Injection, rather than on a client's name. The format is the one I'd hand a client: threat model, findings ranked by severity, how each was reproduced, and what to do about it. Everything below is a real, current result, run the morning this was published against today's ImageMagick (7.1.2) and Pillow (11.3.0), not carried over from an older write-up.
Payload source and exact reproduction code stay in the GitHub repo, under its own authorized-research framing. This report describes what the tests found and what they mean, the way a client deliverable would.
Scope and Objective
Target: an image-ingestion pipeline that accepts user-supplied PNGs and runs them through a sanitization step before the image reaches a downstream consumer, in this case a vision-language model's context window.
Objective: determine which classes of injected payload survive each of four common sanitization strategies, and rank the surviving classes by how hard they are to detect and stop.
Out of scope: the VLM's own prompt-injection handling once a payload reaches its input (a separate engagement), and any pipeline not represented in the four tested below.
Threat Model
An attacker who can get an image into the pipeline (upload, scrape, shared link) wants one of three outcomes: inject instructions a downstream model will read as part of its prompt, exfiltrate data through a channel that bypasses visual review, or evade a content-moderation classifier that only looks at pixels. None of these require compromising the pipeline itself, only surviving whatever sanitization sits in front of it.
Four sanitization pipelines were tested, chosen because they represent what most teams actually run, not a hardened reference implementation:
| Pipeline | What it does |
| --- | --- |
| imagemagick_strip | convert -strip, the one-line fix most teams reach for first |
| imagemagick_full | strip plus an explicit chunk-exclusion list for tEXt/iTXt/zTXt/iCCP |
| pillow_reopen | decode and re-encode through Pillow, metadata untouched |
| pillow_reopen_no_exif | decode and re-encode through Pillow with EXIF explicitly dropped |
Seven payload techniques were tested against all four: EXIF UserComment injection, PNG tEXt/iTXt chunk injection, a custom polyglot chunk, invisible-contrast text, micro-typography tiling, channel-isolated text, and adversarial pixel perturbation.