Skip to main content

CAGE: Credential-bound Agent Gating Engine

Credential containment for AI agents. Capability-token-gated, structurally refusing, audit-chained.

We don't filter what the agent says. We cage what the agent can do.

CAGE is AI control infrastructure: the authority layer that decides what an autonomous agent is allowed to do. It sits above secret stores and HSMs, and away from prompt filters. It replaces the persistent API key with short-lived, scope-bound capability tokens, optionally bound to a context. With the broker deployed as DEPLOY.md describes, a prompt-injected or otherwise compromised agent never holds the credential it works with.


What CAGE is

The engine is Rust. Python is the first client. On the Rust backend (the bundled native extension) the master key lives only in Rust-owned memory and never crosses into Python as plaintext. Python is a thin binding that holds capability tokens. It came first because the AI-agent ecosystem (LangChain, the provider SDKs) lives there, and the broker speaks a language-neutral protocol, so clients in other languages can follow. The out-of-process broker goes further: the agent runs in a separate process holding only token IDs, and the key never enters its address space.

  • A Rust-core secret vault. ChaCha20Poly1305 AEAD, zeroize-on-drop, and mlock(2) to keep the master key pinned in RAM.
  • Structural refusal. No secret-bearing operation (an LLM call, a signature, a release signature) runs without a valid capability token for that verb. Tokens are TTL-bound, scope-bound, use-count-bound and revocable. Issuance, use, revocation and the refusals on the secret-bearing and control paths are recorded on a tamper-evident audit chain.
  • A frozen issuance policy that bounds the issuer as well as the agent. The broker reads it from CAGE_ISSUANCE_SCOPES at start and refuses to start without one, unless the operator waives it with CAGE_BROKER_ALLOW_NO_POLICY=1 (allow_no_policy=True in spawn_broker). The audit chain records the waiver. Allowed scope namespaces and the TTL, use and per-scope lifetime ceilings are then fixed, and no setter exists. A remote caller who later reaches the control plane, even with a stolen operator key, cannot widen them. An out-of-policy scope is refused and audited, TTL and use counts are clamped, and the policy's fingerprint is recorded on every issued token. The lifetime ceiling is counted per running instance, so a restart starts it from zero. A malformed policy variable, or an unknown one starting with CAGE_ISSUANCE_, stops the broker at start as well. The policy is a broker feature: the in-process vault and the pure-Python gate have none.
  • A rustls-direct transport for the Anthropic Messages API and OpenAI Chat Completions. The decrypted API key lives only in Zeroizing<Vec<u8>> buffers inside Rust and never crosses into Python. Each provider trusts only root CAs from the organizations named in its DNS CAA records. A secret can be pinned to one provider.
  • An append-only SHA-256 Merkle audit chain of token lifecycle events (issued, used, revoked, rejected), each with a sequence number. In the in-process API, signed checkpoints (checkpoint() and verify_audit_chain_extends()) let a head anchored off-box prove the chain was extended and not truncated or rewritten. The broker offers a signed attestation over its chain head. Automatic anchoring to Sigstore Rekor is planned.

What CAGE is not

  • A prompt filter or content-moderation gateway. Lakera, Lasso and NeMo Guardrails inspect what the agent says. CAGE constrains what the agent can do.
  • A replacement for HashiCorp Vault or AWS Secrets Manager. CAGE sits above them and decides whether a given agent action is permitted at all, wherever the underlying secret is stored.
  • Finished. It is pre-1.0. The known gaps are listed below.

How to think about CAGE

Three terms from capability security and the agent-safety literature place CAGE:

  • It abolishes ambient authority. An agent handed an API key has ambient authority: standing, unscoped power over everything that key can do, usable at any time and invisibly. CAGE replaces it with capability tokens that are verb-bound, short-lived, use-counted and revocable. Authority stops being something the agent holds and becomes a decision made at each action.
  • It keeps the agent secretless. With the broker, started and provisioned outside the agent, the agent's process holds only token IDs. The guarantee underneath is co-location: the authority check and the secret operation are one atomic Rust operation, with no ungated path to the credential. Short-lived tokens alone are policy. Co-location is mechanism.
  • It removes the payoff of the lethal trifecta. Simon Willison names the dangerous combination as private data, untrusted content and the ability to communicate externally (the lethal trifecta). CAGE leaves all three in place and removes the reward: with the broker deployed as DEPLOY.md describes, an agent without a valid token, even one fully driven by a prompt injection, cannot reach the credential it would need to exfiltrate.

CAGE provides process verifiability: cryptographic evidence, on an append-only chain, of what an agent was authorized to do and what it attempted. Whether the agent did the right thing is a separate question for a separate layer. CAGE constrains capability and does not evaluate intent.

Quickstart

import cage gives you the pure-Python authority core, with no native extension and no third-party dependencies. It gates any action with a capability token and a tamper-evident audit chain:

import cage

gate = cage.Gate()
token = gate.issue_token(scope="db.write", context="job-42", ttl_seconds=60, max_uses=1)

gate.authorize_and_charge(token, "db.write")   # authorize + charge one use atomically, or raise CageViolation
do_the_write()                                 # your gated action

The secret-custody and LLM transport ring loads only when you reach for it. LLM calls need the bundled native extension, and the pure-Python fallback refuses them:

from cage import vault

vault.store_secret("llm_api_key", api_key)  # encrypts into Rust-owned memory

# Fail-closed by default: unseal once for the bootstrap (the authority root),
# then pass it to every issue_token / revoke. On the Rust backend unseal()
# returns an opaque handle, so the secret stays in Rust memory.
# In production, broker_only_issuance=True routes issuance through the
# out-of-process broker so the authority never lives in your process.
bootstrap = vault.unseal()

token = vault.issue_token(
    scope="llm.evaluate",
    context="security-audit-run-42",
    ttl_seconds=60,
    max_uses=3,
    bootstrap_token=bootstrap,
)

# The decrypted key never crosses into Python.
# provider= selects the transport ("anthropic" by default, "openai" also wired).
response = await vault.invoke_llm(token, {
    "model": "claude-haiku-4-5",
    "max_tokens": 200,
    "messages": [{"role": "user", "content": "..."}],
})

For the strongest containment, run the out-of-process broker. The key lives in a separate process and the agent holds only token IDs. cage.broker.spawn_broker starts it, and cage.adapters.CagedAnthropic / CagedOpenAI take the provider SDKs' call shape (they return the provider's JSON as a dict). The broker needs an issuance policy, so set CAGE_ISSUANCE_SCOPES (for example llm.,sign.) before you start it. See examples/broker_demo.py, which drives a real agent child process that is refused every escalation, and examples/agent_broker_adapter.py. Read DEPLOY.md before running the broker in production: it only keeps the key from a same-user agent when the agent cannot control how the broker starts.

Threat model in one paragraph

CAGE is built to contain a compromised agent: an LLM agent driven by prompt injection, or agent code that turned hostile, running in its own process and possibly as the same OS user as the broker. Against that agent the broker keeps the key out of reach, provided the agent cannot write the broker binary, its launcher or its environment (see DEPLOY.md). A remote attacker holding the operator key is bounded by the frozen issuance policy, where one is provisioned. Root, the kernel, and anyone who controls how the broker starts are out of scope. CAGE does not claim to defeat an adversary with unrestricted code execution on the host. It aims to make credential compromise slow and visible.

Known limitations

These are the gaps as of v0.1. Reports and fixes are welcome (see SECURITY.md).

Host and deployment

  • Root, a kernel exploit, or a process that controls how the broker starts (binary, launcher, environment, LD_PRELOAD) can read or subvert the broker. On Linux the broker is dumpable between execve and its own hardening call. Host configuration closes that window (DEPLOY.md).
  • A same-user agent can kill the broker. Audit entries not yet anchored off-box are lost, and a restart starts the issuance lifetime ceiling from zero.
  • The broker socket is 0600, so CAGE_BROKER_ALLOWED_UIDS has no effect yet, and broker responses are not signed.
  • mlock requires CAP_IPC_LOCK. Without it CAGE warns and continues, unless CAGE_STRICT_MLOCK is set.

Key handling

  • During an LLM call the decrypted provider key is resident from the decrypt until the request is written: up to about 50 s of network time on a stalled connection, longer if the process is stopped. That window is not mlocked.
  • Plaintext request bytes transit rustls' reusable write buffer.
  • TLS to the providers is classical. No provider offers post-quantum key exchange on its API endpoint yet.
  • The vault's AEAD uses no associated data, so an attacker who can write the broker's memory can swap ciphertexts between secret names.

Authority and audit

  • The Rust API lets a caller holding an invoke reservation settle it more than once. The Python and broker paths settle exactly once.
  • A failed connection or TLS handshake refunds the use, with no cap, so a one-use token can retry a failing call indefinitely.
  • An operator signature can be replayed if the broker's wall clock is rolled back.
  • The provider pin binds a secret's name, and secrets are unpinned by default.
  • The CA allowlist filters on the root CA only, by organization name. Subordinate CAs run by other organizations under an admitted root are accepted, and revocation is not checked.
  • In-process, register_scope_secret and the audit writer need no authority. In-process code is trusted. The broker exposes neither.
  • vault.consume() still exists for scopes without a Rust transport. It is deprecated, refused by default, and will be removed before 1.0.

Verifying signed releases

Every CAGE wheel published on GitHub Releases is signed with Sigstore through GitHub Actions OIDC and Fulcio. The signing is keyless: no long-lived signing key exists in the repo or in CI. Every signature is recorded in the public Rekor transparency log.

To verify a downloaded wheel before installing:

cosign verify-blob \
  --certificate cage_ai-X.Y.Z-*.whl.cert \
  --signature   cage_ai-X.Y.Z-*.whl.sig \
  --certificate-identity-regexp \
    "https://github.com/derdelean/cage/\.github/workflows/release\.yml@.*" \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com \
  cage_ai-X.Y.Z-*.whl

A passing verification proves the wheel was built by this repository's release workflow at the tagged commit, and the proof is publicly recorded in Rekor. The same workflow publishes to PyPI through trusted publishing (no API token), and PyPI shows a Sigstore attestation for each file. CAGE proposes credential containment through capability tokens and an audit chain, and its own releases are signed with the same Sigstore, Fulcio and Rekor model.

Installing

From PyPI (the distribution is named cage-ai, the import stays import cage):

pip install cage-ai

Or install a signed wheel from GitHub Releases (verify it first, as above), or build from source:

uv pip install maturin
maturin develop --release

A bare import cage (the authority core) needs no native extension. The vault and transport ring load it on first use.

To use CAGE from another local project, build a wheel and install it:

maturin build --release                      # -> target/wheels/cage_ai-0.1.2-*.whl
pip install target/wheels/cage_ai-0.1.2-*.whl

or reference the checkout as a path dependency:

# pyproject.toml of the consuming project (uv)
[tool.uv.sources]
cage-ai = { path = "../cage" }

Locally built wheels are not signed.

License and patents

CAGE is open-source under the Apache License 2.0. Two Swiss patent applications are pending, filed on 21 October 2025 and 19 September 2026. They will not be enforced offensively against good-faith users. See PATENT_PLEDGE.md for the binding defensive-only pledge, modeled on Tesla's 2014 EV patent pledge and the Open Invention Network.

Status

Pre-1.0. The API may change.


Apache 2.0 with a defensive-only patent pledge. Built in Switzerland.

Metadata

Release files for cage-ai 0.1.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for cage-ai 0.1.2
File Size Uploaded Provenance
cage_ai-0.1.2.tar.gz 173.6 kB With provenance Details

Built distributions (wheels)

Table of built distributions (wheels) for cage-ai 0.1.2
File
cage_ai-0.1.2-cp314-cp314-manylinux_2_28_x86_64.whl CPython 3.14 CPython 3.14 Linux glibc 2.28+ x86-64 Details
cage_ai-0.1.2-cp314-cp314-macosx_11_0_arm64.whl CPython 3.14 CPython 3.14 macOS 11.0+ ARM64 Details
cage_ai-0.1.2-cp313-cp313-manylinux_2_28_x86_64.whl CPython 3.13 CPython 3.13 Linux glibc 2.28+ x86-64 Details
cage_ai-0.1.2-cp313-cp313-macosx_11_0_arm64.whl CPython 3.13 CPython 3.13 macOS 11.0+ ARM64 Details
cage_ai-0.1.2-cp312-cp312-manylinux_2_28_x86_64.whl CPython 3.12 CPython 3.12 Linux glibc 2.28+ x86-64 Details
cage_ai-0.1.2-cp312-cp312-macosx_11_0_arm64.whl CPython 3.12 CPython 3.12 macOS 11.0+ ARM64 Details
cage_ai-0.1.2-cp311-cp311-manylinux_2_28_x86_64.whl CPython 3.11 CPython 3.11 Linux glibc 2.28+ x86-64 Details
cage_ai-0.1.2-cp311-cp311-macosx_11_0_arm64.whl CPython 3.11 CPython 3.11 macOS 11.0+ ARM64 Details

Total release size: 9.1 MB

Release files / cage_ai-0.1.2.tar.gz

Download URL cage_ai-0.1.2.tar.gz
Size 173.6 kB
Tags Source
SHA-256 checksum
How to use checksums
8a543799c7b66853026429fdbe496ee71e8c52b48c6c946d24812f3dae050820
BLAKE2b-256 checksum
How to use checksums
7a79c4935e2515e027494568b70059d91b86bb70bcdc25ca7bf5407ca5bcdf24
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 24, 2026.

Transparency log

Release files / cage_ai-0.1.2-cp314-cp314-manylinux_2_28_x86_64.whl

Download URL cage_ai-0.1.2-cp314-cp314-manylinux_2_28_x86_64.whl
Size 1.2 MB
Tags CPython 3.14 Linux glibc 2.28+ x86-64
SHA-256 checksum
How to use checksums
b97c9215d60f1b1314d980663e6398ed8e8a9af6c78f7fb5b6a729e6c15b92ff
BLAKE2b-256 checksum
How to use checksums
81f517a638af411c8938df11ebadda5a060f3c0ba78fe36042380bc739a079f1
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 24, 2026.

Transparency log

Release files / cage_ai-0.1.2-cp314-cp314-macosx_11_0_arm64.whl

Download URL cage_ai-0.1.2-cp314-cp314-macosx_11_0_arm64.whl
Size 1.0 MB
Tags CPython 3.14 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
7c606350ae3d912cd369f70ab9b8d9d18061283493775243060e34eb46c9db7a
BLAKE2b-256 checksum
How to use checksums
3eaef3c0a8ddc8d8377e36dceea457079dd279aa21f88a1643aea39f85b26dfa
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 24, 2026.

Transparency log

Release files / cage_ai-0.1.2-cp313-cp313-manylinux_2_28_x86_64.whl

Download URL cage_ai-0.1.2-cp313-cp313-manylinux_2_28_x86_64.whl
Size 1.2 MB
Tags CPython 3.13 Linux glibc 2.28+ x86-64
SHA-256 checksum
How to use checksums
7a75b7417fc5b7fd0912d6a51ec861aa124254154e72b3a96bb3af3d3c48d9f0
BLAKE2b-256 checksum
How to use checksums
f8ebec6e15fd7524876bd2ca727ffee6e9aec48d0257159f6daf04d61d1d54d5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 24, 2026.

Transparency log

Release files / cage_ai-0.1.2-cp313-cp313-macosx_11_0_arm64.whl

Download URL cage_ai-0.1.2-cp313-cp313-macosx_11_0_arm64.whl
Size 1.0 MB
Tags CPython 3.13 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
56fd82550ca0bc4eaf22fcf530fa71a462aad9c1ad91a177642940ca6e8da584
BLAKE2b-256 checksum
How to use checksums
f1fdf4150a7fc796c9968e9038428c71cdec961de4f1e5e928967796f0c2fc4f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 24, 2026.

Transparency log

Release files / cage_ai-0.1.2-cp312-cp312-manylinux_2_28_x86_64.whl

Download URL cage_ai-0.1.2-cp312-cp312-manylinux_2_28_x86_64.whl
Size 1.2 MB
Tags CPython 3.12 Linux glibc 2.28+ x86-64
SHA-256 checksum
How to use checksums
2901f3b604ff2f2d05f9da4a485d7a52d7dbfbac7bf93031adf78c99d4777bf9
BLAKE2b-256 checksum
How to use checksums
b75c6c5feed9a85327c03a8cf57e2bc799ef569f2a02307d5f5f01d2a6b1072b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 24, 2026.

Transparency log

Release files / cage_ai-0.1.2-cp312-cp312-macosx_11_0_arm64.whl

Download URL cage_ai-0.1.2-cp312-cp312-macosx_11_0_arm64.whl
Size 1.0 MB
Tags CPython 3.12 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
540f3d5b30c469b2b63f097fcdf8037c665c0a63170475170c21c25f94329eac
BLAKE2b-256 checksum
How to use checksums
61944affc6b7315a92e4d80b6a050c7bb24752e599b8b162623eb08d0bcd6dd2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 24, 2026.

Transparency log

Release files / cage_ai-0.1.2-cp311-cp311-manylinux_2_28_x86_64.whl

Download URL cage_ai-0.1.2-cp311-cp311-manylinux_2_28_x86_64.whl
Size 1.2 MB
Tags CPython 3.11 Linux glibc 2.28+ x86-64
SHA-256 checksum
How to use checksums
f5f16f8a4bc4f0be68a7bcb1d064de1b863da53911110798d3d2999125615884
BLAKE2b-256 checksum
How to use checksums
ee5b8b8ddfe621699673da8816b22f79b9cf2f80ab41b95be9c7ed90f4fa0415
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 24, 2026.

Transparency log

Release files / cage_ai-0.1.2-cp311-cp311-macosx_11_0_arm64.whl

Download URL cage_ai-0.1.2-cp311-cp311-macosx_11_0_arm64.whl
Size 1.0 MB
Tags CPython 3.11 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
eb0a383d42302f74c57e0f68828b54361fc86a9f3ef26ee5d6d68f93e2acf4c4
BLAKE2b-256 checksum
How to use checksums
261820898ba301b09c92db0221bb3ec51918d7a7fdfd614554e9f94c35bf3361
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 24, 2026.

Transparency log

Security for cage-ai 0.1.2

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 9 files in this release have been uploaded with provenance metadata.

Select from 9 files

Attestation for cage_ai-0.1.2.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 24, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.2 This release

9 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page