10 releases
| new 0.1.0-alpha.10 | Mar 10, 2026 |
|---|---|
| 0.1.0-alpha.9 | Mar 5, 2026 |
| 0.1.0-alpha.3 | Feb 27, 2026 |
#342 in Development tools
Used in 3 crates
(2 directly)
84KB
1.5K
SLoC
Parry
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.
Prerequisites
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
Install
cargo-binstall
cargo binstall parry-ai
From source
# 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
Nix (home-manager)
# 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" ];
# 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).
Setup
1. Configure HuggingFace token
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-injection
2. Add Claude Code hook
Add 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.
What each hook does
- 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
Daemon & Cache
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.
Detection Layers
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
Scan modes
| 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.
Config
Global flags
| Flag | Env | Default | Description |
|---|---|---|---|
--threshold |
PARRY_THRESHOLD |
0.7 | ML detection threshold (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) |
Subcommand flags
| 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-only
| 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).
ML Backends
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-fetch
Performance
Apple 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.
Development
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 hooks
ML end-to-end tests
The ML e2e tests are #[ignore]d by default since they require a HuggingFace token and model downloads. To run them:
HF_TOKEN=hf_... just e2e
This tests both fast (DeBERTa only) and full (DeBERTa + Llama PG2) modes with semantic injection prompts and clean text. First run downloads models (~100MB each).
Credits
- 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.
License
MIT
Llama Prompt Guard 2 (used in full scan mode) is licensed separately under the Llama 4 Community License. See LICENSE-LLAMA.
Dependencies
~35–56MB
~1M SLoC