Runtime security for developers who ship with AI.
Your AI coding assistant can read your SSH keys, leak your AWS credentials, and run up a $10,000 API bill before you notice. Sanctum watches for all of it -- silently, in the background, without slowing you down.
curl -fsSL https://raw.githubusercontent.com/postrv/sanctum-oss/main/scripts/install.sh | sh
sanctum init
# That's it. The daemon starts with your shell.In one week (March 24--31, 2026), three major supply chain attacks hit the ecosystems developers use every day:
- LiteLLM (March 24) -- Compromised PyPI credentials injected a malicious
.pthfile into Python'ssite-packages. Every time the interpreter started -- evenpython3 --version-- it ran attacker code that stole SSH keys, cloud tokens, and.envfiles. (CVE-2026-33634, CVSS 9.4) - Telnyx Python SDK (March 27) -- Malicious PyPI versions used audio steganography (payload hidden in WAV files) for credential theft. Same threat actor (TeamPCP) leveraging CI/CD secrets stolen from an earlier Trivy compromise.
- Axios (March 31) -- Maintainer account takeover on npm. Two malicious versions of the most popular HTTP client (~100M weekly downloads) added a phantom dependency whose
postinstallscript deployed a cross-platform RAT. Live for under 3 hours, but the blast radius was enormous. (GHSA-fw8c-xr5c-95f9)
These attacks worked because nothing was watching at the moment code ran.
Sanctum watches.
Monitors every Python site-packages directory for new or modified .pth files. Each line is classified as benign (import-only), suspicious (dynamic code), or critical (exec/eval/network). Critical files are quarantined immediately and replaced with empty stubs.
When a .pth file appears, Sanctum traces the process lineage to determine who created it. pip install creating a .pth? Expected. Python startup silently writing new .pth files? That's the attack.
$ sanctum review
Quarantined items (1 total):
------------------------------------------------------------------------
ID: a1b2c3d4
Original: /usr/lib/python3/site-packages/evil-package.pth
Reason: CRITICAL: exec(open('/tmp/.payload').read())
Quarantined: 2026-03-28 14:23:01
------------------------------------------------------------------------
Actions:
sanctum review --approve <ID> — restore file to original location
sanctum review --delete <ID> — permanently remove quarantined file
AI coding assistants hallucinate package names. Sanctum checks every npm install, pip install, go get, and cargo add command against the real registry before execution. Non-existent packages are blocked -- stopping typosquatting and AI-hallucinated package installs before they run.
Beyond existence checks, Sanctum enforces install-time safety across ecosystems:
| Ecosystem | Protection |
|---|---|
| npm | Blocks installs without --ignore-scripts (the axios attack vector) |
| pip | Warns/blocks installs without --only-binary :all: (prevents setup.py execution) |
| Cargo | Warns when new crates with build.rs are downloaded at compile time |
| Docker | Warns on :latest/untagged images, untrusted registries, and unsafe Dockerfile patterns |
Shell-aware command splitting detects chained commands (cd /tmp && npm install evil) that would otherwise bypass detection.
Scans all content passing through AI tool hooks against 37 credential patterns -- OpenAI, Anthropic, AWS, GitHub, Stripe, Slack, GCP, Azure, Docker Hub, Vault, and more. Catches secrets before they leave your machine, not after they're in a training set.
Also runs Shannon entropy analysis to detect high-entropy strings that look like secrets, even when they don't match a known pattern.
$ echo '{"command": "cat ~/.aws/credentials"}' | sanctum hook pre-bash
{"decision":"block","reason":"Reads sensitive credential path: ~/.aws/credentials"}
Tracks per-provider, per-session, and daily spend across OpenAI, Anthropic, and Google APIs. Set budget thresholds, get alerts at configurable percentages, restrict which models each provider can use.
$ sanctum budget
Provider Session Spend Session Limit Daily Spend Daily Limit
openai $8.20 $30.00 $12.40 $100.00
anthropic $4.20 $20.00 $4.20 $100.00
Monitors access to ~/.ssh, ~/.aws/credentials, ~/.kube/config, and other sensitive paths. When an unexpected process touches your credentials, you'll know.
Detects outbound connections on unusual ports, to blocklisted destinations, or from unexpected processes. Uses configurable rules-based detection with safe port allowlists and process allowlists.
Tracks cumulative bytes sent per destination host within a sliding time window. Configurable thresholds trigger warnings (default 5MB) or blocks (default 20MB) with desktop notifications and audit logging. Alert suppression prevents notification floods, and a 10K host cap bounds memory usage.
Sanctum provides pre- and post-tool hooks for Claude Code:
sanctum hooks install claudeThis installs five hook handlers:
| Hook | What it does |
|---|---|
pre-bash |
Blocks credential access, env var exfiltration, slopsquatting, dangerous commands, Docker image safety |
pre-write |
Prevents writes to sensitive paths, detects credential injection, Dockerfile linting |
pre-read |
Blocks reads of SSH keys, cloud credentials, private keys |
pre-mcp |
Enforces MCP tool policies, audits all invocations |
post-bash |
Scans command output for leaked credentials, cargo build.rs warnings, extracts API spend |
A malicious repo config cannot disable these protections -- Sanctum enforces a security floor that project-local configs cannot lower.
sanctum init # Set up Sanctum in your project
sanctum status # Daemon status (works offline too)
sanctum doctor # Health check your installation
sanctum scan # Scan project for credential exposure
sanctum review # Review quarantined threats
sanctum run -- <cmd> # Run a command with protections active
sanctum config # View config (--edit to modify, --recommended for defaults)
sanctum audit # Threat event log (--last 24h, --level critical, --json)
sanctum fix list # Unresolved threats (--category, --level, --json)
sanctum fix resolve <id> # Remediate a threat (--action restore|delete|dismiss)
sanctum fix all --yes # Batch-remediate all unresolved threats
sanctum budget # View current spend
sanctum budget set # Set session/daily limits
sanctum budget extend # Extend session budget
sanctum budget reset # Reset counters
sanctum hook <action> # Hook handler (called by Claude Code, not you)
sanctum hooks install claude # Install Claude Code hooks
sanctum hooks remove claude # Remove Claude Code hooks
sanctum daemon start|stop|restart
sanctum proxy start|status # stop: terminate the proxy process manually# .sanctum/config.toml
[sentinel]
watch_pth = true
watch_credentials = true
watch_network = false # network anomaly detection (opt-in)
pth_response = "quarantine" # quarantine | alert | log
# [sentinel.cargo]
# allowlist = ["my-internal-crate"]
# warn_build_scripts = true # warn on new crate downloads (build.rs risk)
# [sentinel.pip]
# warn_source_installs = true # warn about setup.py execution risk
# require_binary_only = false # set true to block pip without --only-binary :all:
[ai_firewall]
redact_credentials = true
claude_hooks = true
mcp_audit = true
check_package_existence = true # slopsquatting detection (npm, pip, go, cargo)
[[ai_firewall.mcp_rules]]
tool = "filesystem_write"
restricted_paths = ["/etc/*", "/usr/*", "~/.ssh/*"]
[ai_firewall.docker]
trusted_registries = ["docker.io", "ghcr.io", "gcr.io", "public.ecr.aws", "registry.k8s.io"]
warn_latest = true # warn on :latest or untagged images
[budgets]
default_session = "$50"
default_daily = "$200"
alert_at_percent = 75
[budgets.providers.openai]
session = "$30"
daily = "$100"
allowed_models = ["gpt-5.4", "gpt-5.4-mini"][sentinel.network]
exfiltration_warn_bytes = 5242880 # 5MB — desktop notification
exfiltration_block_bytes = 20971520 # 20MB — block + audit event
exfiltration_window_secs = 60 # sliding window (1-3600s)[[ai_firewall.mcp_cel_rules]]
expression = 'tool_name == "filesystem_write" && paths.exists(p, p.startsWith("/etc"))'
action = "deny"
[[ai_firewall.mcp_cel_rules]]
expression = 'payload_size > 1048576'
action = "warn"CEL expressions are non-Turing-complete and have no side effects. Available context variables: tool_name (string), paths (list of strings), payload_size (int).
Generate a recommended starting config with sanctum config --recommended.
Full configuration reference: see sanctum config --recommended for annotated defaults.
git clone https://github.com/postrv/sanctum-oss
cd sanctum-oss
cargo build --release
# Binaries: target/release/sanctum, target/release/sanctum-daemonRequires Rust 1.94.0+ (pinned in rust-toolchain.toml).
curl -fsSL https://raw.githubusercontent.com/postrv/sanctum-oss/main/scripts/install.sh | shThe installer verifies SHA-256 checksums (mandatory) and Sigstore signatures (if cosign is installed). See SECURITY.md for the verification model.
# Add to your ~/.zshrc (or ~/.bashrc, ~/.config/fish/config.fish):
eval "$(sanctum init --shell zsh)"
# Install Claude Code hooks:
sanctum hooks install claudeSee the Getting Started guide for a complete walkthrough.
Sanctum runs as a background daemon that starts with your shell. The daemon watches the filesystem, monitors processes, and serves an IPC socket for the CLI and hook handlers.
Claude Code Your shell
| |
[pre-bash hook] [shell hook]
| |
sanctum hook ----IPC----> sanctum-daemon
| | |
.pth watch | credential watch
|
network monitor
The CLI is stateless -- it talks to the daemon over a Unix socket. Hook handlers are fast (single IPC round-trip) so they don't slow down your AI coding session.
Sanctum composes with nono.sh for kernel-level sandboxing:
# nono: kernel sandbox + phantom proxy
# sanctum: runtime monitoring + AI firewall + budget control
nono run --profile claude-code -- claudeSanctum does not require nono. Each tool provides independent value.
8 crates, ~51,000 lines of Rust, 5 ecosystem integrations (npm, pip, Go, Cargo, Docker):
| Crate | Purpose |
|---|---|
sanctum-cli |
CLI interface -- 14 commands via clap |
sanctum-daemon |
Background daemon, IPC server (14 commands), event loop |
sanctum-sentinel |
.pth monitoring, quarantine, credential watching, network anomaly detection |
sanctum-firewall |
Credential redaction (37 patterns), Shannon entropy, MCP policy engine, slopsquatting detection (4 registries), Docker image safety |
sanctum-budget |
Spend tracking, 3 provider parsers (OpenAI, Anthropic, Google) |
sanctum-proxy |
HTTP budget proxy with body limits, credential redaction, budget enforcement, SSRF prevention, and usage extraction |
sanctum-types |
Shared types, config schema, threat model, platform paths |
sanctum-notify |
Cross-platform desktop notifications (macOS + Linux) |
Sanctum is a security tool. It holds itself to a higher standard than the code it protects.
Compile-time guarantees (enforced by workspace lints -- not conventions, compiler errors):
- Zero
unsafecode - No
unwrap(),expect(), orpanic!()outside tests - No
print!()/println!()/eprint!()-- all output goes through structured channels
Testing:
- 2,000+ tests (unit, integration, end-to-end, loom concurrency)
- 9 Kani bounded model checking proofs (panic-freedom, state machine correctness, overflow safety)
- 2 fuzz targets on security-critical parsers (CI runs 30s per target on PRs, 2.5h nightly)
- 9 property-based tests verifying core invariants across random inputs
- 0 clippy warnings (pedantic + nursery lints enabled)
Supply chain:
- All dependencies audited and version-pinned (344 crates in Cargo.lock)
cargo-denyenforces license policy and advisory database checks in CI- Sigstore-signed release binaries with SBOM and Rekor transparency log
- Reproducible builds verified in CI (build twice, compare SHA-256)
Documentation:
- SECURITY.md -- Vulnerability reporting and security guarantees
- THREAT_MODEL.md -- What Sanctum does and doesn't protect against
- ARCHITECTURE.md -- Design decisions with security rationale
- DEPENDENCY_AUDIT.md -- Every dependency justified
Sanctum is open source under the MIT license. Contributions are welcome.
Before submitting a PR, ensure:
cargo fmt --all -- --check
cargo clippy --all-targets --all-features # must be 0 warnings
cargo test --all --all-features # must passThe workspace lint configuration is strict by design. If clippy complains, fix the code -- don't suppress the lint.
MIT -- see LICENSE.