Skip to content
Sanctum

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.

Diagram: OAuth secures the client-to-MCP front door while plaintext keys sit unguarded on the back path to downstream APIs.
OAuth secured the front door. Your keys sit unguarded on the back.
Diagram: Sanctum vault sits in the last-mile gap, injects credentials in transit, secret stays sealed.
Sanctum stands in that gap — local vault, inject in transit.
Today — animated
FRONT DOOR · SECUREDBACK DOOR · NO STANDARDClient / AgentMCP ServerDownstreamOAuth 2.1plaintext .env keysno lease · no audit · forever valid
With Sanctum — animated
SECRET NEVER CROSSES THIS LINEClient / AgentMCP ServerSanctum vaultsealedDownstreamOAuth 2.1use · handleinject in transitholds lease onlysecret sealed here

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.

  1. 01

    use(service)

    Your agent asks the vault for a handle — never the secret itself.

  2. 02

    Handle + proxyBaseUrl

    You get a lease-bound URL and session token scoped to that agent.

  3. 03

    Normal API call

    Point your SDK at the vault. Credential is injected vault-side in transit.

Sanctum path — handle only · inject in transit
SANCTUM USE · SECRET STAYS IN THE VAULTAgent / MCPlease + proxyBaseUrlhandle onlySanctum vaultinject in transitDownstreamuse()no secretinject in transitnever holds the keysecret sealed herereal API · 200 OK

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

example.pysanctum-sdk
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 key

Want 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.

Sanctum admin console: policy stat strip, rule builder, dry-run against recent traffic, and active rules on a dark emerald and gold UI.
Write policy from what your agents are actually doing — dry-run it against real recent traffic before you enable it.
Admin console — full page
Full Sanctum Data-Access Policy page including live activity feed.
Rule builder
Rule builder UI for composing data-access policy conditions and graduated actions.
Dry-run
Dry-run panel evaluating a candidate rule against real recent agent traffic before enabling it.
Live activity feed
Live agent-activity feed with matched policy rule per event.

Graduated actions

Not every anomaly needs a hard kill. Escalate from record → notify → human gate → deny → quarantine.

  1. 01flag

    Recorded, not blocked — surface risk without stopping the request.

  2. 02alert

    Notify operators when behavior crosses a threshold you define.

  3. 03require-approval

    Hold the request until a human signs off.

  4. 04deny

    Block the call. The lease stays valid for other allowed work.

  5. 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.

Active rules
Active data-access rules list in the Sanctum admin console with status and action grades.

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.

Presets
Use-not-retrieve · simulationLIVE
AGENT research-botLEASE active

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.

permissivebalancedstrict

Default posture for most teams.

Engine decision

ALLOW · inject credential · write audit event

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.

View clients on GitHub →
example.pysanctum-sdk
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 key

Security & 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, VaultLLM gatewaysPortkey, LiteLLM, OpenRouterSanctum
Agents hold the raw keyYes (they hand it back)OftenNo — a handle, never the secret
Inspects what's done with accessNoPrompt/routing onlyYes — SQL, model, egress, inline
Data-classification-aware policyNoNoYes (flag→…→quarantine)
RelationshipSanctum sits on the same "agents don't see keys" base, and adds inspection + policySanctum 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.

Before · secrets in the agent path.env
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
After · handle onlySanctum or CRP provider
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. 1 · Run Sanctum — local vault, policy, audit. The product path — no open-standard adoption required.
  2. 2 · Keep your workflows — same SDKs and tools; secrets inject in transit instead of living in the agent.
  3. 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