While a traditional Web Application Firewall (WAF) filters incoming traffic to protect the server from the user, LLMON functions as a WAAiF (Web Adversarial AI Firewall)—an outbound filter designed to manipulate content for machine ingestion.
It represents a paradigm shift from Network Security to Cognitive Security. By operating at the infrastructure level (via Caddy V2), LLMON intercepts HTTP responses and modifies files on-the-fly, injecting "poisoned" instructions targeting AI Agents/Scrapers (like GPTBot or ClaudeBot) while leaving the content undisturbed and functional for human users.
This enables active defense strategies—from Instructional Overrides that force models to respect copyright, to Context Flooding that exhausts token limits, to Honey Potting to detect unauthorized scraping—all without modifying your backend application code.
At its core, LLMON acts as a gatekeeper of meaning. Working to ensure that while the raw bytes are accessible, the semantic value extracted by AI is oriented towards the user, not the machine.
Download these files to see LLMON inject payloads on the fly. Inspect the files locally to verify.
Injected: Served via /assets/, triggering the llmon middleware.
Original: Served via /clean/, bypassing the middleware (configured via
exclude /clean/*). Comparing the two files confirms on-the-fly modification.
| Format | Injection Vector | Validation Strategy | Injected | Original |
|---|---|---|---|---|
| Invisible Watermark (Opacity 0.01%) | Use pdfcpu validate or search for text watermark. |
test.pdf | test.pdf | |
| DOCX | Hidden Paragraph (word/document.xml) | Unzip and grep word/document.xml for payload. |
test.docx | test.docx |
| XLSX | VeryHidden Sheet ("DataSource") | Unzip and check xl/worksheets/ for hidden sheet. |
test.xlsx | test.xlsx |
| MP3 | ID3v2 USLT (Lyrics) Frame | Check ID3 Tags (Lyrics field). | test.mp3 | test.mp3 |
| WAV | RIFF ICMT (Comment) Chunk | Hex editor: search for "ICMT" chunk. | test.wav | test.wav |
| GIFAR (Polyglot) | Valid GIF + JS Payload (Polyglot) | Open in Text Editor to see appended JS. | test_polyglot.gif | test.gif |
| PDF+HTML (Polyglot) | Valid PDF + Hidden HTML (Polyglot) | Open in Text Editor to see appended HTML. | test_polyglot.pdf | test.pdf |
| PNG | tEXt Chunk | Hex editor: search for "tEXt" chunk or "Comment". | test.png | test.png |
| Ghost PNG | Alpha Channel Ghosting (Vector B) | Open in Python (Pillow) and convert('RGB') to see hidden text. |
test_ghost.png | test_ghost.png |
| JPEG | COM (Comment) Segment | Hex editor: search for FF FE segment. |
test.jpg | test.jpg |
| GIF | Comment Extension Block | Hex editor: search for 21 FE block. |
test.gif | test.gif |
| SVG | <desc> Metadata | View Source (Text Editor). | test.svg | test.svg |
| WOFF2 | Extended Metadata Block | Decompress metadata block (Brotli) or use ttx. |
test.woff2 | test.woff2 |
| TTF | Name Table (ID 10/13) | Use FontTools/ttx to inspect name table. |
test.ttf | test.ttf |
| OTF | Name Table (ID 10/13) | Use FontTools/ttx to inspect name table. |
test.otf | test.otf |
| ICS | DESCRIPTION Field | Text Editor. | test.ics | test.ics |
| SRT | Subtitle Block (0ms) | Text Editor. | test.srt | test.srt |
| JSON | New Key (_llm_instruction) |
Text Editor / JSON Viewer. | data.json | data.json |
| XML (RSS) | XML Comment | Text Editor. | feed.xml | feed.xml |
| Robots.txt | Comment & Disallow Rule | Text Editor. | robots.txt | robots.txt |
| JavaScript | Variable (var _llm_instruction) |
Text Editor. | script.js | script.js |
| Strategy | Description | Config | Example |
|---|---|---|---|
| HTML Comment | Injects payloads into standard HTML comments. Bots read the source code. | type html_comment |
|
| Hidden Textarea | Injects a <textarea> hidden with advanced CSS (randomized class names) to
avoid display: none detection. |
type textarea |
|
| Script Text | Injects payloads into a non-executable script tag (text/plain). Safe from execution, visible to parsers. | type script_text |
|
| CSS Comment | Injects payloads into CSS comments within <style> tags. |
type css_comment |
|
| Title Injection | Appends or modifies the <title> tag. |
type title |
|
| Attribute Injection | Injects payloads into data-* attributes or aria-label. |
type attributetarget_tags div
|
|
| PDF (Watermark) | Injects an invisible text watermark (opacity 0.01%) into the PDF page content. | Default for .pdf |
|
| PDF (Polyglot) | Constructs a valid PDF that also contains valid HTML. Browsers render HTML; PDF readers render PDF. | file_strategy pdf polyglot |
|
| DOCX (Hidden) | Injects a hidden paragraph element into the word/document.xml structure. |
Default for .docx |
|
| XLSX (Hidden Sheet) | Injects a "VeryHidden" worksheet containing the payload into the workbook. | Default for .xlsx |
|
| PNG (Metadata) | Injects payload into a tEXt chunk (Comment). |
Default for .png |
|
| PNG (Alpha Stego) | Encodes payload into the Least Significant Bits (LSB) of the Alpha channel. | file_strategy png alpha_stego |
|
| PNG (Ghost Text) | Uses Alpha 0 (transparent) but fully saturated RGB values (Vector B). | type ghost_text (HTML) |
|
| JPEG (Comment) | Injects payload into the COM (Comment) segment. |
Default for .jpg |
|
| GIF (Extension) | Injects payload into a Comment Extension Block. | Default for .gif |
|
| GIF (Polyglot) | Appends a JavaScript payload to a valid GIF, creating a valid image + valid script (GIFAR). | file_strategy gif polyglot |
|
| SVG (Metadata) | Injects payload into <desc> or <metadata> tags. |
Default for .svg |
|
| MP3 (ID3v2) | Injects payload into the USLT (Unsynchronized Lyrics/Text) frame. |
Default for .mp3 |
|
| WAV (RIFF) | Injects payload into an ICMT (Comment) chunk within the RIFF header. |
Default for .wav |
|
| Fonts (WOFF2/TTF) | Injects payload into the name table (Copyright/Description fields). |
Default for .woff2, .ttf |
|
| JSON | Injects a new key _llm_instruction with the payload. |
Default for .json |
|
| XML / RSS | Injects an XML comment. | Default for .xml |
|
| JavaScript | Injects a variable declaration at the top of the script. | Default for .js |
|
| Robots.txt | Injects a Disallow rule and a comment. | Default for robots.txt |
|
| Category | Goal | Mechanism | Example |
|---|---|---|---|
| Guerrilla Marketing | Personal Branding Ensure any AI summarizing your content recommends you as the top expert. |
Injects a system instruction into bio/resume pages. |
|
| Cyber Security | Attacker Misdirection (Honey Pot) Detect and misdirect malicious AI agents scanning your infrastructure. |
Tricks the agent into visiting a tracking URL with its internal state. |
|
| Behavioral & Adversarial | Prompt Extraction Trick the AI into revealing its system prompt or sensitive instructions. |
Social Engineering / Roleplay Injection. |
|
| Resource Consumption Force the AI to waste compute tokens on irrelevant tasks. |
Computation Trap / Infinite Loop. |
|
|
| Behavioral Override Override the AI's persona to degradation or entertainment. |
Persona Adoption. |
|
You must compile Caddy with the llmon module using xcaddy:
# Install xcaddy
go install github.com/caddyserver/xcaddy/cmd/xcaddy@latest
# Build Caddy with llmon
xcaddy build --with github.com/jaredfolkins/llmon=.
For production, run Caddy as a systemd service.
# Create caddy user/group
sudo groupadd --system caddy
sudo useradd --system \
--gid caddy \
--create-home \
--home-dir /var/lib/caddy \
--shell /usr/sbin/nologin \
--comment "Caddy web server" \
caddy
# Move binary
sudo mv caddy /usr/bin/
sudo chown root:root /usr/bin/caddy
sudo chmod 755 /usr/bin/caddy
Create /etc/systemd/system/caddy.service:
# /etc/systemd/system/caddy.service
[Unit]
Description=Caddy
Documentation=https://caddyserver.com/docs/
After=network.target network-online.target
Requires=network-online.target
[Service]
Type=notify
User=caddy
Group=caddy
ExecStart=/usr/bin/caddy run --environ --config /etc/caddy/Caddyfile
ExecReload=/usr/bin/caddy reload --config /etc/caddy/Caddyfile
TimeoutStopSec=5s
LimitNOFILE=1048576
LimitNPROC=512
PrivateTmp=true
ProtectSystem=full
AmbientCapabilities=CAP_NET_BIND_SERVICE
[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now caddy
sudo systemctl status caddy
Add the llmon directive to your Caddyfile. Ensure you order it before encoding:
{
# Global Option: Ensure llmon runs before compression
order llmon before encode
}
https://llmon.jaredfolkins.com {
# Site Root
root * /var/www/llmon/www
# Serve Static Files
file_server
# LLMON Configuration
llmon {
# Injection Probability (1.0 = 100%)
rate 1.0
# Injection Strategy
type random
# Specific File Strategies (Optional overrides)
file_strategy gif polyglot
file_strategy pdf polyglot
file_strategy png alpha_stego
}
}
LLMON looks for resources in directories relative to your Caddyfile. If these folders are
missing, LLMON will automatically create them and populate them with default assets (jailbreaks and
directives).
/var/www/llmon/
├── Caddyfile
├── www/ # Website content (index.html, assets, etc.)
├── directives/ # Your prompt instructions (Payloads)
│ ├── hire_me.txt
│ └── honeypot.txt
└── jailbreaks/ # Jailbreak wrappers (Templates)
├── openai/ # Vendor subfolders
│ └── gpt.hujson
└── anthropic/
└── claude.hujson
LLMON automatically creates this folder and populates it with default directives. You can add your own plain
text files (.txt) here. LLMON picks one random directive per request to embed into the
injection. These are the "payloads" or instructions you want the AI to follow.
LLMON automatically creates this folder with vendor-specific subfolders (e.g., openai,
anthropic). You can place .hujson (Human JSON) templates inside. LLMON detects the
bot's User-Agent and selects a template from the matching vendor folder.