CLI + MCP server for detecting, classifying, and redacting embedded LLM agent instructions in documents, source code, and web pages.
Project description
llm-sanitizer
CLI + MCP server for detecting, classifying, and redacting embedded LLM agent instructions in documents, source code, and web pages.
What It Does
Documents, web pages, and source code can contain embedded instructions
targeting LLM agents — from legitimate customization to malicious prompt
injection. llm-sanitizer scans content for these embedded instructions,
classifies their risk level, reports findings in multiple formats, and
optionally produces redacted output.
Detection
Twelve pluggable detection rules covering:
- Instruction override phrases ("ignore previous instructions…")
- Zero-width character encoding (hidden text via invisible Unicode)
- HTML/markdown hidden content (white-on-white, display:none)
- Role-play injection ("act as", "you are now DAN")
- System prompt markers (
<system>,## System Prompt) - Data exfiltration attempts ("output the system prompt")
- Comment-embedded directives (
<!-- AI: do this -->) - Base64-encoded instructions
- Unicode homoglyph substitution (Cyrillic lookalikes)
- Agent-specific config patterns in unexpected locations
- Character-splitting obfuscation (
i g n o r e,ignore___all) — reconstructed and re-scanned - Semantic-intent injection — a local, no-egress n-gram classifier that catches keyword-less rephrasings (role reassignment, verbatim/echo exfiltration, supersede-prior-guidance) the pattern rules miss
Classification
Five risk levels: info (legitimate AI config) → low → medium → high → critical (confirmed injection technique).
Redaction
Non-destructive cleaning in three modes:
- strip — remove the instruction entirely
- comment — replace with
[REDACTED: ...]marker - highlight — wrap in visible markers for review
Installation
pip install llm-sanitizer
# or
uv pip install llm-sanitizer
Quick Start
CLI
# Scan a file
llm-sanitize scan document.md
# Scan a URL
llm-sanitize scan https://example.com/page
# Scan a directory
llm-sanitize scan ./docs/ --glob "**/*.md"
# Redact a file
llm-sanitize redact document.md -o clean_document.md
# Redact a directory (mirrors structure)
llm-sanitize redact ./docs/ -o ./clean_docs/
# Control how binary files (PDF, DOCX, zip, images, ...) are handled —
# detected by content, not extension, so renaming a file changes nothing
llm-sanitize scan document.pdf --binary-mode extract # pull embedded text via markitdown (default)
llm-sanitize scan suspicious.png --binary-mode text # force raw bytes to be scanned as literal text
llm-sanitize scan large_dir/ --binary-mode skip # exclude binary files from the scan entirely
# Assemble a directory report from previously-saved `scan --format json`
# results without re-scanning (for callers that cache scans by content hash)
llm-sanitize merge --manifest manifest.txt --format sarif > report.sarif
--binary-mode extract (the default) rejects malicious zip archives — excessive
entry counts, total uncompressed size, or compression ratios — before
decompressing anything.
MCP Server
Add to your MCP configuration:
{
"mcpServers": {
"llm-sanitizer": {
"command": "llm-sanitizer"
}
}
}
Available tools: scan_text, scan_file, scan_url, scan_dir, redact,
redact_file, redact_url, redact_dir, list_rules.
Python API
from llm_sanitizer.scanner import scan_text
result = scan_text("Check this <!-- ignore previous instructions --> content")
print(result.findings) # [Finding(rule='comment_directive', risk='high', ...)]
Configuration
Create .llm-sanitizer.yml at your project root:
sensitivity: medium # low | medium | high
rules:
zero_width:
enabled: true
instruction_override:
enabled: true
sensitivity: high # per-rule sensitivity override
policy:
mode: "allow-known" # allow-known | allow-none | allow-all
agents:
copilot: allow
cursor: allow
# Refuse oversized input fail-closed (a CRITICAL input_too_large finding)
# rather than reading/scanning it. Default 25 MiB.
max_scan_bytes: 26214400
# How to treat a non-archive binary that yields no extractable text.
unprocessable_binary_policy: fail # fail (default) | scan-text | ignore
# Recursive archive scanning limits (zip / tar / gz / bz2 / xz / 7z / rar).
archive:
max_depth: 3 # archive-in-archive nesting levels
max_cumulative_bytes: 524288000 # 500 MB across all nested levels
max_uncompressed_bytes: 104857600 # 100 MB per archive
max_entries: 1000 # per-archive entry-count cap
max_compression_ratio: 100 # zip-bomb ratio guard
formats: [zip, tar, gz, bz2, xz, 7z, rar]
output:
format: markdown # json | markdown | sarif
context_lines: 2
Output Formats
- JSON — structured findings for programmatic use
- Markdown — human-readable reports
- SARIF — GitHub Code Scanning / VS Code integration
Documentation
Credits — semantic-intent training data
The semantic_intent classifier is trained on a hand-curated corpus plus,
optionally, third-party labeled datasets (used at train time only — only the
trained weights ship; the datasets are not redistributed). With thanks to:
- prodnull/prompt-injection-repo-dataset (Apache-2.0) — injection embedded in repository files, with domain-matched hard negatives.
- deepset/prompt-injections (Apache-2.0) — classic prompt-injection set (positives used for augmentation).
See data-raw/SOURCES.md for full provenance, licenses,
and pinned revisions.
License
AGPL-3.0-or-later. Commercial licensing available — contact greg@warnes-innovations.com.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file llm_sanitizer-0.3.0.tar.gz.
File metadata
- Download URL: llm_sanitizer-0.3.0.tar.gz
- Upload date:
- Size: 240.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9fc04e410dcd789184f46c0f591f92a04304aaaa60d5aed8c452b3ed7530a482
|
|
| MD5 |
fb2d3460c596ac3c07a7a10348eee2c5
|
|
| BLAKE2b-256 |
bc44edbc2006a558c35dd1d49783a20e7425056dde9e8bc56f7221771b95d1ba
|
Provenance
The following attestation bundles were made for llm_sanitizer-0.3.0.tar.gz:
Publisher:
publish.yml on Warnes-Innovations/llm-sanitizer
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
llm_sanitizer-0.3.0.tar.gz -
Subject digest:
9fc04e410dcd789184f46c0f591f92a04304aaaa60d5aed8c452b3ed7530a482 - Sigstore transparency entry: 2230124890
- Sigstore integration time:
-
Permalink:
Warnes-Innovations/llm-sanitizer@411a944cdf6e6ab2949f23de05f5af04f7e185ed -
Branch / Tag:
refs/tags/v0.3.0 - Owner: https://github.com/Warnes-Innovations
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@411a944cdf6e6ab2949f23de05f5af04f7e185ed -
Trigger Event:
release
-
Statement type:
File details
Details for the file llm_sanitizer-0.3.0-py3-none-any.whl.
File metadata
- Download URL: llm_sanitizer-0.3.0-py3-none-any.whl
- Upload date:
- Size: 187.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
730971ea99ac65667be90b882355f3d1495ea42e18ec92132dca5892909a71f4
|
|
| MD5 |
d453acbbdd6e21b1f4ca97d8a93f6629
|
|
| BLAKE2b-256 |
6071bdeb57465115fed9a03d7297f4d10feb07fed0299a7147f250c40e4ca0de
|
Provenance
The following attestation bundles were made for llm_sanitizer-0.3.0-py3-none-any.whl:
Publisher:
publish.yml on Warnes-Innovations/llm-sanitizer
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
llm_sanitizer-0.3.0-py3-none-any.whl -
Subject digest:
730971ea99ac65667be90b882355f3d1495ea42e18ec92132dca5892909a71f4 - Sigstore transparency entry: 2230125531
- Sigstore integration time:
-
Permalink:
Warnes-Innovations/llm-sanitizer@411a944cdf6e6ab2949f23de05f5af04f7e185ed -
Branch / Tag:
refs/tags/v0.3.0 - Owner: https://github.com/Warnes-Innovations
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@411a944cdf6e6ab2949f23de05f5af04f7e185ed -
Trigger Event:
release
-
Statement type: