Image Techniques¶
hemlock provides four hiding techniques for PNG images, targeting metadata injection and steganographic embedding. Image-based attacks target multimodal RAG pipelines that ingest screenshots, diagrams, scanned documents, or other visual content alongside their metadata.
Technique Overview¶
| Technique | Stealth | Description |
|---|---|---|
text-chunk |
55 | Payload in PNG tEXt Description chunk |
xmp-metadata |
60 | Payload in XMP dc:description via PNG iTXt chunk |
multi-chunk |
65 | Payload distributed across Title, Author, Description, Comment chunks |
steganographic |
90 | Payload encoded in least-significant bits of pixel data |
text-chunk¶
How It Works¶
PNG files support ancillary text chunks (tEXt) that store key-value metadata. hemlock injects the payload as a Description tEXt chunk inserted between the IHDR and IDAT chunks. Most image viewers ignore these chunks, but document processing pipelines that extract metadata will read them.
The technique generates a gradient PNG carrier image, then inserts a tEXt chunk:
Framework Survival¶
Image metadata extraction is pipeline-dependent. Standard text-extraction frameworks (LangChain, LlamaIndex, Unstructured, Haystack) do not natively extract PNG metadata, but multimodal pipelines and custom loaders that parse image metadata will encounter the payload.
CLI Example¶
hemlock craft \
--format image \
--technique text-chunk \
--payload override \
--count 1 \
--output ./image-test
Detection¶
Inspect PNG chunks with tools like pngcheck or Python's PIL:
xmp-metadata¶
How It Works¶
XMP (Extensible Metadata Platform) is an ISO standard for embedding metadata in media files. hemlock injects the payload inside XMP XML as the dc:description field, stored in a PNG iTXt (international text) chunk with the keyword XML:com.adobe.xmp.
<x:xmpmeta xmlns:x="adobe:ns:meta/">
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<rdf:Description rdf:about=""
xmlns:dc="http://purl.org/dc/elements/1.1/">
<dc:description>PAYLOAD TEXT</dc:description>
</rdf:Description>
</rdf:RDF>
</x:xmpmeta>
Framework Survival¶
XMP metadata is widely supported by media management tools and some document processing pipelines. Pipelines using exiftool, Adobe libraries, or XMP-aware extractors will encounter the payload.
CLI Example¶
hemlock craft \
--format image \
--technique xmp-metadata \
--payload exfiltrate \
--count 1 \
--output ./xmp-test
Detection¶
Extract XMP with exiftool:
multi-chunk¶
How It Works¶
Instead of placing the entire payload in a single metadata field, multi-chunk distributes the payload across four PNG tEXt chunks: Title, Author, Description, and Comment. Each chunk contains a fragment of the full payload, making detection harder since no single metadata field contains the complete injection.
PNG Signature
IHDR
tEXt: Title = <fragment 1>
tEXt: Author = <fragment 2>
tEXt: Description = <fragment 3>
tEXt: Comment = <fragment 4>
IDAT
IEND
The payload is split into roughly equal parts using word boundaries.
Framework Survival¶
Pipelines that concatenate all metadata fields during extraction will reassemble the full payload. Pipelines that extract individual fields will see only fragments, which may still influence LLM behavior depending on the payload design.
CLI Example¶
hemlock craft \
--format image \
--technique multi-chunk \
--payload override \
--count 1 \
--output ./multi-test
Detection¶
Inspect all text chunks:
steganographic¶
How It Works¶
The highest-stealth image technique. The payload is encoded directly into the least-significant bits (LSB) of pixel color channels. hemlock uses 2 bits per RGB channel (6 bits per pixel), encoding a magic header (0xBEEF), a 4-byte length prefix, and the payload bytes.
The encoding is invisible to human viewers because modifying the 2 least-significant bits of each color channel produces imperceptible color shifts. However, the data can be extracted by any tool that reads pixel values.
Pixel encoding (2 bits per channel):
R: bits[0:2] of data
G: bits[2:4] of data
B: bits[4:6] of data
Header: 0xBEEF (magic) + uint32(payload_length) + payload_bytes
Requires lossless format
LSB steganography requires a lossless image format like PNG. JPEG compression destroys the least-significant bit patterns. All image techniques in hemlock use PNG output.
Framework Survival¶
Standard metadata extractors will not find the payload because it exists only in pixel data. Detection requires steganographic analysis tools or custom extraction code that reads LSB patterns.
CLI Example¶
hemlock craft \
--format image \
--technique steganographic \
--payload override \
--count 1 \
--output ./stego-test
Detection¶
Steganographic payloads require specialized detection:
- Statistical analysis: Chi-squared tests on LSB distributions
- Visual inspection: Enhanced LSB plane visualization
- Custom extraction: Read the 2 LSBs from each RGB channel and check for the
0xBEEFmagic header
Image Format Notes¶
All image techniques produce PNG files (.png). PNG is chosen because:
- Lossless compression preserves both metadata chunks and LSB steganographic data
- Ancillary chunk support (tEXt, iTXt) provides standardized metadata injection points
- Go stdlib support —
image/pngin the Go standard library handles encoding/decoding without external dependencies
The carrier image is a 320x240 gradient PNG with colors derived from the cover text, providing visual variety across generated documents.
Next Steps¶
- Techniques Overview — Full technique matrix across all formats
- CLI Craft — Generate image documents from the command line
- API Formats — Use the image package programmatically