OAuth secured the front door. Your API keys are wide open on the back.
The data-access firewall for AI agents.
Your agents use credentials without ever holding them — and everything they do with that access is inspected, gated, and audited inline. Local-first, drops into the stack you already run.
v0.12 · pre-1.0 · no third-party audit yet
The gap
The last-mile credential problem
Every MCP server, framework, and .env holds raw keys. One prompt injection, one malicious tool, one leaked file — and the key is gone, valid forever, replayable anywhere.


OAuth secured the front door (client → server). The server still needs your GitHub token, your database password — and those sit in plaintext on the back. A door OAuth never covered. Sanctum stands in that gap — as a local tool you run yourself, not a cloud silo.
How Sanctum works
Use, don't retrieve
Sanctum is a local vault you run next to your agents. Point your SDK's base URL at it → the vault injects the real key in transit → the secret never reaches the agent. Not disk, not memory, not the wire. Install and use — no protocol adoption required.
Built to adapt to your setup: MCP servers, coding agents, gateways, existing API clients. Thin use() + a proxy URL — not a heavyweight reconfiguration project.
- 01
use(service)
Your agent asks the vault for a handle — never the secret itself.
- 02
Handle + proxyBaseUrl
You get a lease-bound URL and session token scoped to that agent.
- 03
Normal API call
Point your SDK at the vault. Credential is injected vault-side in transit.
Point your SDK at the vault
A leaked handle is bounded by a lease (TTL + scope + instant revoke) and only works throughthe vault — it can't be replayed off-host (the proxy is loopback-bound by default).
Python · also TypeScript, Rust, Go
from sanctum_sdk import VaultClientfrom openai import OpenAI with VaultClient("my-agent") as sanctum: h = sanctum.use("openai") # → a handle, never the secret client = OpenAI(base_url=h.proxy_base_url, # point the SDK at the vault api_key=h.token) # your session, not the key client.chat.completions.create(...) # vault injects the real keyWant the same last-mile pattern as an open standard across MCP tools and other vaults? See how CRP fits — optional →
Data-access policy
Gate behavior inline
Because Sanctum is the injection point, every request is already bound to an agent identity, a lease, and a data classification. Write policy over what agents do — not just which keys they hold.





Graduated actions
Not every anomaly needs a hard kill. Escalate from record → notify → human gate → deny → quarantine.
- 01flag
Recorded, not blocked — surface risk without stopping the request.
- 02alert
Notify operators when behavior crosses a threshold you define.
- 03require-approval
Hold the request until a human signs off.
- 04deny
Block the call. The lease stays valid for other allowed work.
- 05quarantine
Kill the lease. Instant cascade revoke — that agent is done.
Dry-run before you enforce
Test any rule against real recent traffic before enabling it. See which agents would have matched — then flip the switch.
~10µs to evaluate a 1,000-rule policy set
inline, no tax on the hot path.

Interactive policy lab
Because the vault is the chokepoint, policy can see behavior
Feel free to choose combinations of traffic below to see how enforcement would play out for real agent tasks. Conditional policy is meant to stay flexible while preserving strong controls — we are early on these features and expect more in releases ahead.
Simulation only — not live daemon output. Same graduated ladder the product uses: flag → alert → require-approval → deny → quarantine. Dry-run real rules against recent traffic before you enforce them in production.
Try out several policy presets and watch the interactive policy engine react to the traffic and issue a decision below. You can also pick any agent, operation, and posture yourself.
Watch the loop: gray request enters the vault → red secrets stay sealed inside → teal handle is all that continues outbound. The agent never receives plaintext.
Typical research agent — internal data only.
Ordinary model traffic — low risk when clearance fits.
Default posture for most teams.
Engine decision
Score 1 (risk + clearance gap + posture) · demo formula for illustration
flag
Allow the call, record the risk, surface it in the activity feed.
alert
Notify operators when behavior crosses a threshold you define.
require-approval
Hold the request until a human reviews and signs off.
deny
Block this call. The lease can still serve other allowed work.
quarantine
Revoke the lease immediately, including delegated descendants.
SDKs
Four Sanctum SDKs
Python, TypeScript, Rust, and Go — all thin: use(service) returns a handle, never a secret. Same idea in every language; drop into the clients you already use.
API shape aligns with CRP v0.2 for ecosystem interop — you still just install Sanctum and call use().
- Pythonsanctum-sdk
pip install sanctum-sdk - TypeScript@sanctumai/sdk
npm install @sanctumai/sdk - Rustsanctum-sdk
cargo add sanctum-sdk - Gosdk/go
go get github.com/SanctumSec/sanctum/sdk/go - CLIinstall.sh
curl -fsSL https://raw.githubusercontent.com/SanctumSec/sanctum/main/scripts/install.sh | sh
Same shape in every language
Get a lease-bound handle, point your existing SDK at proxyBaseUrl, keep calling the API the way you already do. The vault injects the real credential in transit.
from sanctum_sdk import VaultClientfrom openai import OpenAI with VaultClient("my-agent") as sanctum: h = sanctum.use("openai") # → a handle, never the secret client = OpenAI(base_url=h.proxy_base_url, # point the SDK at the vault api_key=h.token) # your session, not the key client.chat.completions.create(...) # vault injects the real keySecurity & trust
Local-first by design
Your secrets stay on the machine you control. The architecture is public. The claims are scoped to what is actually shipped.
Local-first runtime
Loopback only. No cloud, no account, no telemetry. Single Rust binary on Linux, macOS, and Windows.
Vault crypto
AES-256-GCM for secrets. SQLCipher for metadata. Scrypt (N=2¹⁸) for passphrase KDF.
Agent identity
Ed25519-bound agent identity. Cryptographic leases with cascade revocation.
Audit log
Hash-chained and Ed25519-signed. Every gate decision leaves a durable trail.
Hardened proxy
SSRF-hardened egress. Leases only work through the vault — not replayable off-host (loopback-bound by default).
Operator safeguards
Real recovery phrase. 12-char passphrase floor. Core dumps disabled. Optional idle auto-lock.
Positioning
How it's different
Sanctum is a different layer — it composes with what you run.
| Secret managers1Password, Infisical, Vault | LLM gatewaysPortkey, LiteLLM, OpenRouter | Sanctum | |
|---|---|---|---|
| Agents hold the raw key | Yes (they hand it back) | Often | No — a handle, never the secret |
| Inspects what's done with access | No | Prompt/routing only | Yes — SQL, model, egress, inline |
| Data-classification-aware policy | No | No | Yes (flag→…→quarantine) |
| Relationship | Sanctum sits on the same "agents don't see keys" base, and adds inspection + policy | Sanctum sits beneath them — keep your gateway; it holds the keys | — |
A compromised gateway holding Sanctum leases instead of raw keys is a contained incident, not a breach.
Optional · open standard
Catch what config still misses
You do not need this to run Sanctum. Install the vault, call use(), point your tools at it — that product path works today on its own.
We kept asking about the places you don't see: MCP servers with long-lived keys, gateways that rehydrate secrets, scripts that never hit the vault. Wouldn't it be better if the last mile could enroll automatically?
That's why we proposed the Credential Resolution Protocol (CRP) — an enhancement to MCP so clients and servers can use credentials without holding them, and so secrets land in a vault (Sanctum or any CRP-capable provider) instead of scattered configs. Sanctum is the product you install now. CRP is the open path so the ecosystem can catch up.
OPENAI_API_KEY=sk-live-••••••••
# agent / MCP server / gateway holds the key
client = OpenAI() # default env pickup- in .env
- in process memory
- replayable if leaked
h = vault.use("openai")
client = OpenAI(
base_url=h.proxy_base_url,
api_key=h.token, # session — not the key
)- handle only
- inject in transit
- lease-bound
Same SDK shape. A few lines of configuration. The secret never enters the agent process — whether you use Sanctum today or a future CRP-capable vault.
Enhancement, not a rewrite
CRP extends how MCP-shaped systems handle the credential last mile. Client→server OAuth stays as-is; the back door finally has a standard.
Catch the blind spots
Tool servers, gateways, and one-off scripts that never hit your vault. The goal: enroll secrets and inject in transit by design — not by hope.
Same few lines of shape
use() + a proxy URL. Existing SDKs keep working. Change how credentials are obtained — not your whole agent stack.
Open + multi-vendor
Proposed to the MCP working group. Sanctum is a reference implementation; any vault can offer the same use-not-retrieve pattern.
How it fits together
- 1 · Run Sanctum — local vault, policy, audit. The product path — no open-standard adoption required.
- 2 · Keep your workflows — same SDKs and tools; secrets inject in transit instead of living in the agent.
- 3 · CRP when you care about the ecosystem — same behavior described as an open protocol so any provider can interoperate; Sanctum remains the concrete reference.
MCP working group · discussion #2246 · proposed · SanctumSec
