Prompt injection scanner for Claude Code hooks. Scans tool inputs and outputs for injection attacks, secrets, and data exfiltration attempts.
Early development — this tool is under active development and may have bugs or false positives. Tested on linux/macOS.
The ML models are gated on HuggingFace. Before installing:
- Create an account at huggingface.co
- Accept the DeBERTa v3 license (required for all modes)
- For
fullmode: also accept the Llama Prompt Guard 2 license (Meta approval required) - Create an access token at huggingface.co/settings/tokens
cargo binstall parry-aiNo Rust toolchain needed. Install rvx, then use it directly in hooks — it downloads the pre-built binary on first run and caches it:
{
"hooks": {
"PreToolUse": [{ "command": "rvx parry-ai --bin parry -- hook", "timeout": 1000 }],
"PostToolUse": [{ "command": "rvx parry-ai --bin parry -- hook", "timeout": 5000 }],
"UserPromptSubmit": [{ "command": "rvx parry-ai --bin parry -- hook", "timeout": 2000 }]
}
}Environment variables (HF_TOKEN, PARRY_IGNORE_PATHS, etc.) are inherited as normal.
# Default (Candle backend - pure Rust, no native deps)
cargo install --path crates/cli
# ONNX backend (faster inference, needs native libs)
cargo install --path crates/cli --no-default-features --features onnx-fetch# flake.nix
{
inputs.parry.url = "github:vaporif/parry";
outputs = { parry, ... }: {
# pass parry to your home-manager config via extraSpecialArgs, overlays, etc.
};
}# home-manager module
{ inputs, pkgs, config, ... }: {
imports = [ inputs.parry.homeManagerModules.default ];
programs.parry = {
enable = true;
package = inputs.parry.packages.${pkgs.system}.default; # candle (default)
# package = inputs.parry.packages.${pkgs.system}.onnx; # onnx backend (5-7x faster, see Performance)
hfTokenFile = config.sops.secrets.hf-token.path;
ignorePaths = [ "/home/user/repos/parry" ];
# claudeMdThreshold = 0.9; # ML threshold for CLAUDE.md scanning (default 0.9)
# scanMode = "full"; # fast (default) | full | custom
# Custom models (auto-sets scanMode to "custom")
# models = [
# { repo = "ProtectAI/deberta-v3-small-prompt-injection-v2"; }
# { repo = "meta-llama/Llama-Prompt-Guard-2-86M"; threshold = 0.5; }
# ];
};
}You still need to configure the Claude Code hook separately (see below).
One of (first match wins):
export HF_TOKEN="hf_..." # direct value
export HF_TOKEN_PATH="/path/to/token" # file path
# or place token at /run/secrets/hf-token-scan-injectionAdd to ~/.claude/settings.json:
{
"hooks": {
"PreToolUse": [{ "command": "parry hook", "timeout": 1000 }],
"PostToolUse": [{ "command": "parry hook", "timeout": 5000 }],
"UserPromptSubmit": [{ "command": "parry hook", "timeout": 2000 }]
}
}The daemon auto-starts on first scan, downloads the model on first run, and idles out after 30 minutes.
Note (non-Nix users): The Nix home-manager module wraps the binary with all config baked in via env vars. Without Nix, set env vars in your shell profile (e.g.
HF_TOKEN,PARRY_IGNORE_PATHS,PARRY_SCAN_MODE) — the hook command inherits them. Alternatively, pass flags directly in the hook command:parry --hf-token-path ~/.hf-token --ignore-path /home/user/safe hook. See Config for all options.
- PreToolUse: 5-layer security — taint enforcement, CLAUDE.md scanning, exfil blocking, sensitive path blocking, input content injection scanning (Write/Edit/Bash/MCP tools)
- PostToolUse: Scans tool output for injection/secrets, auto-taints project on detection
- UserPromptSubmit: Audits
.claude/directory for dangerous permissions, injected commands, hook scripts
The daemon keeps ML models in memory and can be run standalone with parry serve --idle-timeout 1800. Hook calls auto-start it if not running.
Scan results are cached in ~/.parry/scan-cache.redb (30-day TTL, ~8ms cache hits vs ~70ms+ inference). Cache is shared across projects and pruned hourly.
Multi-stage, fail-closed (if unsure, treat as unsafe):
- Unicode — invisible characters (PUA, unassigned codepoints), homoglyphs, RTL overrides
- Substring — Aho-Corasick matching for known injection phrases
- Secrets — 40+ regex patterns for credentials (AWS, GitHub/GitLab, cloud providers, database URIs, private keys, etc.)
- ML Classification — DeBERTa v3 transformer with text chunking (256 chars, 25 overlap) and head+tail strategy for long texts. Configurable threshold (default 0.7).
- Bash Exfiltration — tree-sitter AST analysis for data exfil: network sinks, command substitution, obfuscation (base64, hex, ROT13), DNS tunneling, cloud storage, 60+ sensitive paths, 40+ exfil domains
- Script Exfiltration — same source→sink analysis for script files across 16 languages
| Mode | Models | Latency/chunk |
|---|---|---|
fast (default) |
DeBERTa v3 | ~50-70ms |
full |
DeBERTa v3 + Llama Prompt Guard 2 | ~1.5s |
custom |
User-defined (~/.config/parry/models.toml) |
varies |
Use fast for interactive workflows; full for high-security or batch scanning (parry diff --full). The two models cover different blind spots — DeBERTa v3 catches common injection patterns while Llama Prompt Guard 2 is better at subtle, context-dependent attacks (role-play jailbreaks, indirect injections). Running both as an OR ensemble reduces missed attacks at ~20x higher latency per chunk.
| Flag | Env | Default | Description |
|---|---|---|---|
--threshold |
PARRY_THRESHOLD |
0.7 | ML detection threshold (0.0–1.0) |
--claude-md-threshold |
PARRY_CLAUDE_MD_THRESHOLD |
0.9 | ML threshold for CLAUDE.md scanning (0.0–1.0) |
--scan-mode |
PARRY_SCAN_MODE |
fast | ML scan mode: fast, full, custom |
--hf-token |
HF_TOKEN |
— | HuggingFace token (direct value) |
--hf-token-path |
HF_TOKEN_PATH |
/run/secrets/hf-token-scan-injection |
HuggingFace token file |
--ignore-path |
PARRY_IGNORE_PATHS |
— | Paths to skip scanning (comma-separated / repeatable) |
| Flag | Env | Default | Description |
|---|---|---|---|
serve --idle-timeout |
PARRY_IDLE_TIMEOUT |
1800 | Daemon idle timeout in seconds |
diff --full |
— | false | Use ML scan instead of fast-only |
diff -e, --extensions |
— | — | Filter by file extension (comma-separated) |
| Env | Default | Description |
|---|---|---|
PARRY_LOG |
warn | Tracing filter (trace, debug, info, warn, error) |
PARRY_LOG_FILE |
~/.parry/parry.log |
Override log file path |
Custom patterns: ~/.config/parry/patterns.toml (add/remove sensitive paths, exfil domains, secret patterns).
Custom models: ~/.config/parry/models.toml (used with --scan-mode custom, see examples/models.toml).
One backend is always required (enforced at compile time). Nix builds candle by default.
| Feature | Description |
|---|---|
candle |
Pure Rust ML. Portable. Default. |
onnx-fetch |
ONNX with auto-download. Works pretty much everywhere. |
onnx |
ONNX, you provide ORT_DYLIB_PATH. |
onnx-coreml |
(experimental) ONNX with CoreML on Apple Silicon. |
# Build with ONNX instead of candle
cargo build --no-default-features --features onnx-fetchApple Silicon, release build, fast mode (DeBERTa v3 only). ONNX is 5-7x faster than Candle. Run just bench-candle / just bench-onnx to reproduce (requires HF_TOKEN).
| Scenario | Candle | ONNX |
|---|---|---|
| Short text (1 chunk) | ~61ms | ~10ms |
| Medium text (2 chunks) | ~160ms | ~32ms |
| Long text (6 chunks) | ~683ms | ~136ms |
| Cold start (daemon + model load) | ~1s | ~580ms |
| Fast-scan short-circuit | ~7ms | ~7ms |
| Cached result | ~8ms | ~8ms |
Llama Prompt Guard 2 (~1.5s/chunk) does not ship an ONNX export, so
fullmode uses Candle for PG2 regardless of backend.
nix develop # enter dev shell with all tools (rust, just, taplo, typos, actionlint)
just check # run all checks (clippy, test, fmt, lint, typos, audit)
just build # build workspace (candle)
just build-onnx # build workspace (onnx-fetch)
just test # run tests
just e2e # run ML e2e tests (requires HF_TOKEN, see below)
just bench-candle # benchmark ML inference, candle backend (requires HF_TOKEN)
just bench-onnx # benchmark ML inference, ONNX backend (requires HF_TOKEN)
just clippy # lint
just fmt # format all (rust + toml)
just setup-hooks # configure git hooksThe ML e2e tests are #[ignore]d by default since they require a HuggingFace token and model downloads. To run them:
HF_TOKEN=hf_... just e2eThis tests both fast (DeBERTa only) and full (DeBERTa + Llama PG2) modes with semantic injection prompts and clean text. First run downloads models (~100MB each).
- ML model: ProtectAI/deberta-v3-small-prompt-injection-v2
- Same model used by LLM Guard
- Exfil patterns: Inspired by GuardDog (Datadog's malicious package scanner)
- Full scan mode optionally uses Llama Prompt Guard 2 86M by Meta, licensed under the Llama 4 Community License. Built with Llama.
MIT
Llama Prompt Guard 2 (used in full scan mode) is licensed separately under the Llama 4 Community License. See LICENSE-LLAMA.