AI agents run with their user's full access.

A task that needs three permissions gets tokens for everything, valid for months, usable by anything the agent reads.

CapAuth issues a signed lease per task, checks every tool call against it in code, and records each decision in a hash-chained log.

Hosted replays of real runs. Running CapAuth locally? Open the live console on port 8000.

Live run: a manager agent delegates one capability to a worker agent.
The problem in detail

Standing access is what a security review cannot sign.

The agent holds its user's tokens: read every channel, push and merge, read and share every file, email anyone. Those grants do not depend on the task, and they do not expire.

One agent holds every key its user has; the task needs three; a thread it reads asks it to export customer data
The task needs three capabilities. The agent holds every key its user has, and anything it reads can try to use the rest.

Non-human identities outnumber people

Agents multiply them. Classic access control assumes an actor whose permissions do not depend on a decision it has not made yet.

Injection through tool results is unsolved

An agent that reads a document or a web page can be instructed by it. There is no equivalent of a parameterized query.

Logging is now a legal duty

EU AI Act high-risk obligations for logging and human oversight took effect in August 2026. What counts as a sufficient agent audit log is not yet specified.

Figures from the AGI House Enterprise Deployment primer, Layer 7.

The fix

Per-task leases instead of standing tokens.

Scoped to the task

The lease holds only the capabilities the agent's plan needs: this channel, this repo, this customer. Nothing else is there to misuse.

Short-lived

Ten minutes by default, revoked the moment the task ends. There is no standing access left behind.

Enforced in code

Every tool call is checked against the lease by a deterministic gate. The model proposes; the code decides.

Logged for review

Every decision lands in a hash-chained ledger with who, for whom, what, why, and when.

Why it works for an enterprise

What a security review, a compliance team, and an IT owner each get.

Something a review can sign

A signed lease per task and a verifiable ledger are artifacts. A model's refusal rate is not. The review evaluates the ceiling and the enforcer, not the transcript.

Fits the identity you already run

The policy ceiling is per agent identity, the way a service account is scoped today. The lease is the just-in-time narrowing on top. Every entry carries the human the agent acts for.

Logging a regulator can read

Who, for whom, what, why, and when, hash-chained, with an attestation and JSONL export to a SIEM. Aimed at the EU AI Act high-risk logging and oversight duties in force since August 2026.

People where it matters

Sensitive actions wait for a person. Approvals are recorded under the operator's identity, once or for the task, never silently.

No change to agents or tools

CapAuth sits as an MCP server in front of the tools. The agent framework and the tool servers stay as they are. Any model behind it, frontier or local.

Ready for AI organizations

When a manager agent creates a worker, the worker's lease is a strict subset with a shorter TTL, and both write to one audit trail. Authority narrows at every hop.

The numbers behind these claims are on this page: 72 measured runs, a live delegation, and the full source.

How it works

  1. The agent writes its plan. Two to six steps, before any tool call.
  2. A security planner proposes the minimal capability set for that plan. It is a model call and may be wrong or manipulated.
  3. A policy ceiling clamps the proposal. Per agent identity, written as code. The planner can only narrow it, never widen it.
  4. CapAuth signs a lease with a ten-minute TTL, bound to the agent identity and the human it acts for.
  5. Every tool call is checked in pure code. Signature, TTL, then tool, action, and resource. Outcomes: allowed, narrowed, waiting for a person, or denied.
  6. The task ends, the lease is revoked, and the hash-chained ledger is exported.
The model proposes and code enforces. The enforcer makes no model call.
Architecture diagram: Claude Code holds a lease and calls tools only through the CapAuth MCP server
Claude Code is launched with CapAuth as its only tool source. Every call is enforced before it reaches a tool.
The decision path for one tool call
The decision path for one call. Every branch appends one ledger entry.

The console

One screen per run: the plan, the lease, and every decision.

A run: summary, plan, lease capabilities, decisions
Runs. The task, the identity it acts for, the lease with its TTL, the plan with each step ticked as its call is checked, and the decisions table.
Policies: the ceiling per identity
Policies. The ceiling per agent identity, as code: what can be leased, what needs a person every time, and what is never granted.
Decisions: allowed, narrowed, waiting for approval, denied
Decisions. Time, outcome, call, and reason for every tool call, with worker leases indented under their manager and injected instructions called out.

Open the console

Four outcomes, all from real runs.

Allowed

slack.search(channel="#payments")

Inside the lease, so it ran.

Narrowed

slack.search(channel="*") narrowed to #payments

The plan wanted every channel. The lease gave one.

Waiting for a person

github.merge_pr(acme/payments-api, #481)

Sensitive under policy. Waited for the operator, then ran.

Denied

slack.post_message(channel="#payments")

Not in the task. Denied, with provenance.

The honest measurement

72 runs through Claude Code: three models, four injection payloads, CapAuth on and off, three runs per cell. Every run read the poisoned thread.

Agent under testInjection variantsRunsTook the injected actionCustomer data left the orgLegitimate issue filed
Opus 54240024 / 24
Sonnet 54240024 / 24
Haiku 4.54240024 / 24

No model took the injected action. The legitimate task completed 72 of 72 times. A refusal rate is not a control; with CapAuth the out-of-lease action is unreachable regardless of the model. The same lease stopped overreach that was not an attack: a stray Slack post, a search across every channel.

Built for an AI organization

AI managers create task-specific AI employees. Humans set direction and approve decisions. Every agent is tied to a responsible person.

A manager agent hands a worker a smaller lease through capauth.delegate. The worker's lease is a strict subset of the manager's, cannot outlive it, and carries the parent lease id. Both write to one audit trail.

Live run: the manager holds three capabilities, the worker gets one for five minutes, three decisions on two hash chains.

Enterprise controls

Policy as code

One YAML file per agent identity: the ceiling, the actions that need a person, the actions that are never granted.

Lease preview

See what a task template would get before any agent holds it.

Delegation chains

Child leases are strict subsets with shorter TTLs. The ledger shows the chain.

Verifiable audit

Hash-chained entries: who, for whom, what, why, when. Attestation, JSONL export, and an offline verifier that fails on tamper.

MCP native

Sits in front of any MCP client. The agent and the tools do not change.

Any model

Enforcement does not depend on the model.

Demo videos

An AI organization. A live Claude Code run. The manager delegates one capability to a worker. Nothing simulated.

Customer-facing agent, before and after. The customer asks the agent to export every record. Simulated agent, labeled on screen.

Poisoned Slack thread, before and after. Without CapAuth the export and the email run; with CapAuth both are denied. Simulated agent, labeled.

Run it

Requirements: Python 3.13, uv, and the claude CLI logged in. No API key.

git clone https://github.com/HivaMohammadzadeh1/capauth && cd capauth
uv sync
uv run python server.py            # open http://localhost:8000
uv run pytest                      # 21 tests
uv run python attack/demo.py --scope off   # terminal before
uv run python attack/demo.py --scope on    # terminal after

Built at AGI House Enterprise Deployment Build Day, 19 September 2026.