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, where the operator provisions one. The broker reads it from CAGE_ISSUANCE_SCOPES at start. 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 stops the broker at start. 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). 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.1-*.whl
pip install target/wheels/cage_ai-0.1.1-*.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.1

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.1
File Size Uploaded Provenance
cage_ai-0.1.1.tar.gz 171.9 kB With provenance Details

Built distributions (wheels)

Table of built distributions (wheels) for cage-ai 0.1.1
File
cage_ai-0.1.1-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.1-cp314-cp314-macosx_11_0_arm64.whl CPython 3.14 CPython 3.14 macOS 11.0+ ARM64 Details
cage_ai-0.1.1-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.1-cp313-cp313-macosx_11_0_arm64.whl CPython 3.13 CPython 3.13 macOS 11.0+ ARM64 Details
cage_ai-0.1.1-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.1-cp312-cp312-macosx_11_0_arm64.whl CPython 3.12 CPython 3.12 macOS 11.0+ ARM64 Details
cage_ai-0.1.1-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.1-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.1.tar.gz

Download URL cage_ai-0.1.1.tar.gz
Size 171.9 kB
Tags Source
SHA-256 checksum
How to use checksums
fd24f3627d8288107cf57714b75428e7af115cfe8612ca419322cd714a0f4de8
BLAKE2b-256 checksum
How to use checksums
8144299226544618a7bbd533f0a35567c7ddf056cc7565f2915b8505be2f057d
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 21, 2026.

Transparency log

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

Download URL cage_ai-0.1.1-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
840f17bf2096816b3552d8c1f33fbc7aff4926cf09b3bd49a7f0f2baadbcadb0
BLAKE2b-256 checksum
How to use checksums
3110e2af22e49a324552e09179175299573138d182d10aed640599233e79bd8e
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 21, 2026.

Transparency log

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

Download URL cage_ai-0.1.1-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
450dd10208c8e0737c6e5314db5bb2ae43ae66e3d5b82a5dd70e7f7d4bf85d61
BLAKE2b-256 checksum
How to use checksums
72883487a37414e1ccaed0c4f5a85faed5fed3fc50ceb7f6b04fb23d8fc819dd
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 21, 2026.

Transparency log

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

Download URL cage_ai-0.1.1-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
7dd8baaa00bb220392bf0119e37a3757b17c4c264496887cb15e6007ab289758
BLAKE2b-256 checksum
How to use checksums
84947ebb859c69c739fab4012266df6ace3a5e62883bd037cc8fcdcc647e368e
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 21, 2026.

Transparency log

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

Download URL cage_ai-0.1.1-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
ffaae8b0bf962b07dc4e1a9b58e2ef455b17518437f0d0d261c4f257ab2435a0
BLAKE2b-256 checksum
How to use checksums
676f03162f34a55cb7bd55bff1e1e4f77a62d12a56e8fa57fc63bbbb10460db3
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 21, 2026.

Transparency log

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

Download URL cage_ai-0.1.1-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
ea5aa43aa1a5bd608f68500f86a9a43ba33b8220e9565b7dd58f0378bfb4fdc8
BLAKE2b-256 checksum
How to use checksums
dd23cf5deab98ee72849e309f747b2f1c05bd301668f7896b91c88e3d7bb5dd1
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 21, 2026.

Transparency log

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

Download URL cage_ai-0.1.1-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
0d1db1400e7e782eec0d4511a81ad83b0cf02e7e192836877e1a0df9d47850f0
BLAKE2b-256 checksum
How to use checksums
1dc5a2703280d06971be1c816566cd53d51fffb4ba70bee1c4ba66d0b821b913
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 21, 2026.

Transparency log

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

Download URL cage_ai-0.1.1-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
0eddb9ef34eed110ddb3a6984004cd22f9d9faf0608fecb6c04ea1e29ae03139
BLAKE2b-256 checksum
How to use checksums
587ce8cb03f32bd7d29ddbca54c064b105ba61a2c2fa91039f13f088c82d03bc
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 21, 2026.

Transparency log

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

Download URL cage_ai-0.1.1-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
a7c6b52d0c3ff9739d305c36d003fc7aee78ff65ec1cf823ff773223ea4fd9f8
BLAKE2b-256 checksum
How to use checksums
df48aab24178e467e9cfe9c92a70ec55aa3b0266b6a43d368b9865217c96f0fb
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 21, 2026.

Transparency log

Security for cage-ai 0.1.1

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.1.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 21, 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.1 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