Skip to content

Commit 57ba75e

Browse files
soc1024claude
andcommitted
docs: rewrite README around intent-based JIT policy and open integration surface
Position against Conseca citation landscape: human approves intent (not code), LLM drafts scoped-fetch specs from trusted context only, deterministic enforcement. Move TEE deploy instructions to dstack/DEPLOY.md. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent f970d67 commit 57ba75e

File tree

2 files changed

+77
-56
lines changed

2 files changed

+77
-56
lines changed

README.md

Lines changed: 59 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,75 @@
11
# OAuth3 Enclave
22

3-
AI agents need real credentials to act on your behalf — but an agent holding your API key is a liability. Prompt injection means any retrieved content could instruct the agent to misuse it. OAuth extensions (OIDC-A, OBO tokens) require every service to upgrade. And revoking a leaked token doesn't undo the damage.
3+
An API gateway where every integration is defined just-in-time. There's no fixed set of tools — an agent states its **intent** (a goal, API doc URLs, and which secrets it needs), a trusted LLM inside the enclave drafts a minimal scoped-fetch spec from only that trusted context, a human approves the intent, and the spec compiles into a deterministic sandbox. Credentials never leave the TEE. The agent never sees them.
44

5-
OAuth3 puts a TEE between the agent and the services. The enclave holds your credentials, the agent never touches them. The agent describes what it wants to do, a human approves a scoped capability, and the agent's code runs inside the enclave's sandbox with only the approved functions available. To external services, it looks like a normal user session — no server changes required.
5+
This is the [Conseca](https://arxiv.org/abs/2501.17070) architecture (Google, HotOS 2025) made concrete: separate trusted policy generation from untrusted execution. The LLM drafts policy using **only trusted inputs** (the intent spec + authoritative API docs). The policy compiles to a locked-down fetch function — specific URL globs, HTTP methods, body fields, rate limits. No LLM in the enforcement path. No predefined tool registry. No server-side changes.
66

77
```
8-
Agent TEE (Confidential VM)
9-
┌──────────┐ ┌─────────────────────────────┐
10-
│ Agent │── capability spec ►│ LLM drafts scoped function │
11-
│ │ │ human approves the spec │
12-
│ │── orchestration ►│ code runs in SES sandbox │
13-
│ │ code │ only approved functions │
14-
│ │◄── result ─────────│ keys never leave enclave │
15-
└──────────┘ └─────────────────────────────┘
8+
Agent Human TEE (Confidential VM)
9+
┌─────────┐ ┌───────────┐ ┌──────────────────────────────┐
10+
│ │── intent ──► │ │ │
11+
│ │ name │ reviews │─approve─►│ LLM drafts scoped-fetch spec │
12+
│ │ goal │ the │ │ from intent + API docs only │
13+
│ │ doc_urls │ intent │ │ (no untrusted input) │
14+
│ │ secrets │ │ │ │
15+
│ │ └───────────┘ │ spec compiles to: │
16+
│ │ │ URL globs, methods, │
17+
│ │ │ body schema, rate limits │
18+
│ │ │ │
19+
│ │──── orchestration code ──────────►│ runs in SES sandbox │
20+
│ │ │ github('GET', '/repos/...') │
21+
│ │◄──── result ─────────────────────│ credentials injected by TEE │
22+
└─────────┘ └──────────────────────────────┘
23+
24+
untrusted ▲ trusted ▲
25+
prompt injection can't attested, deterministic
26+
change the approved spec no LLM at enforcement time
1627
```
1728

18-
### Why not just review the agent's code?
29+
### Intent, not code review
1930

20-
Because code review doesn't help when the code was influenced by prompt injection. The key insight: **the capability function is written before any untrusted data enters the system.** The agent submits a rigid JSON spec, Haiku drafts a 5-line fetch wrapper from authoritative API docs, and the human approves it — all before the agent processes any external content. Injected instructions can't change the approved capability; they can only affect data flowing through it, inside the sandbox.
31+
The human approves a **goal** — "create issues on owner/repo using the GitHub API" — not a page of code. The trusted LLM inside the enclave translates that into a scoped-fetch spec: which base URL, which path globs, which HTTP methods, which body fields, which secrets to inject. That spec is the policy. It compiles to a sandbox function that can't do anything outside its scope.
2132

22-
### Open integration surface
33+
An intent looks like:
34+
```json
35+
{
36+
"name": "github",
37+
"goal": "Create issues on owner/repo",
38+
"doc_urls": ["https://docs.github.com/en/rest/issues"],
39+
"secret_hints": ["GITHUB_TOKEN"]
40+
}
41+
```
42+
43+
The LLM drafts this into a scoped-fetch spec — locked to `POST /repos/owner/repo/issues`, with `Authorization: Bearer {GITHUB_TOKEN}` injected, body restricted to `title` and `body` fields, rate-limited. That's what runs. Nothing else exists in the sandbox.
44+
45+
### Why this matters
2346

24-
Most agent security frameworks assume a **fixed set of tools** — the agent picks from `send_email`, `read_file`, `query_db`, and the security system gates access to that known set. This is true of [Conseca](https://arxiv.org/abs/2501.17070) (Google, HotOS 2025), [Progent](https://arxiv.org/abs/2504.11703), [SEAgent](https://arxiv.org/abs/2601.11893), [MiniScope](https://arxiv.org/abs/2512.11147), [AgentArmor](https://arxiv.org/abs/2508.01249), and others. Their policy languages — whether regex, DSL, or LLM-generated — reference specific tools and endpoints known at policy-definition time.
47+
Every other agent security framework assumes the set of integrations is **known in advance**. [Progent](https://arxiv.org/abs/2504.11703), [SEAgent](https://arxiv.org/abs/2601.11893), [MiniScope](https://arxiv.org/abs/2512.11147), [AgentArmor](https://arxiv.org/abs/2508.01249) — they all gate access to predefined tools. Their policy languages (regex, DSL, Cedar) reference specific tool names and endpoints. This works for closed systems, but agents operating in the real world need to hit APIs nobody anticipated at design time.
2548

26-
OAuth3 doesn't require a predefined tool registry. An agent can propose a novel integration with any HTTP API, and the system handles it: the agent submits a capability spec, the enclave's LLM drafts scoped code from API docs, a human reviews the concrete function, and it runs sandboxed. The set of possible integrations is open-endedbounded only by what a human is willing to approve.
49+
OAuth3 is open-ended: the agent proposes an intent, the human approves a goal, the enclave enforces a spec. The set of possible integrations is unboundedlimited only by what a human is willing to approve.
2750

28-
This also addresses the main critiques the field levels at Conseca's approach:
29-
- **"Regex policies can't handle complex attacks"** ([ControlValve](https://arxiv.org/abs/2510.17276)) — OAuth3 generates executable code, not regex patterns
30-
- **"LLM-generated policies are unreliable"** ([MiniScope](https://arxiv.org/abs/2512.11147), [CSAgent](https://arxiv.org/abs/2509.22256)) — the LLM drafts code that a human reviews and that compiles to deterministic constraints; no LLM in the enforcement path
31-
- **"Domain-specific rules limit open-domain use"** ([PSG-Agent](https://arxiv.org/abs/2509.23614)) — capabilities are generated per-task, not predefined per-domain
51+
This sidesteps the main critiques the field levels at contextual policy generation:
52+
- **"Regex policies can't handle complex attacks"** ([ControlValve](https://arxiv.org/abs/2510.17276)) — the spec compiles to URL globs + method + body schema, enforced deterministically
53+
- **"LLM-generated policies are unreliable"** ([MiniScope](https://arxiv.org/abs/2512.11147), [CSAgent](https://arxiv.org/abs/2509.22256)) — the LLM only drafts from trusted context; a human approves; enforcement has no LLM
54+
- **"Domain-specific rules can't cover open-domain tasks"** ([PSG-Agent](https://arxiv.org/abs/2509.23614)) — intents are generated per-task for any API
3255

33-
### What's unique
56+
### Features
3457

35-
- **Open integration surface**works with any HTTP API without predefined tool definitions. Agents propose novel integrations; humans approve concrete code.
36-
- **No server changes**the enclave holds real credentials and proxies requests. To external services it looks like a normal user session.
37-
- **Credential custody in hardware**secrets live inside a TEE (dstack CVM). Remote attestation proves what code is running.
38-
- **Capability-based sandbox**agent code gets named functions (`github()`, `slack()`), not raw `fetch()`. Each function is locked to specific URL patterns, methods, and body fields.
39-
- **Account encumbrance** — the password can be rotated *inside* the TEE so even the user can't bypass policies without visibly destroying the encumbrance. Enables DAO-controlled accounts, mandatory CI gates, escrow delegation.
58+
- **Open integration surface** — any HTTP API, no predefined tools. Agents propose intents; the enclave drafts specs.
59+
- **Credential custody in hardware**secrets live in a TEE (dstack CVM). Remote attestation proves what code runs.
60+
- **No server changes**to external services it looks like a normal user session.
61+
- **Deterministic sandbox**each approved spec compiles to a named function locked to specific URL globs, methods, body fields, and rate limits. No `fetch()`, no escape.
62+
- **Account encumbrance** — the password can be rotated *inside* the TEE so even the user can't bypass policies without visibly destroying the encumbrance.
4063

4164
## Quick start
4265

4366
```bash
4467
cd proxy && npm install && npm run dev
4568
```
4669

47-
Zero config for local dev — JWT secrets auto-generate, SQLite is embedded. Set `ANTHROPIC_API_KEY` in `.env` if you want the LLM to draft capabilities from natural language intent.
70+
Zero config for local dev — JWT secrets auto-generate, SQLite is embedded. Set `ANTHROPIC_API_KEY` in `.env` for LLM-drafted capabilities.
4871

4972
```bash
50-
# Get tokens
5173
AGENT=$(curl -s -X POST localhost:3737/signup -H 'Content-Type: application/json' \
5274
-d '{"name":"my-agent"}' | jq -r .token)
5375
OWNER=$(curl -s -X POST localhost:3737/signup -H 'Content-Type: application/json' \
@@ -58,16 +80,16 @@ curl -s -X POST localhost:3737/secrets \
5880
-H "Authorization: Bearer $OWNER" -H 'Content-Type: application/json' \
5981
-d '{"name":"GITHUB_TOKEN","value":"ghp_..."}'
6082

61-
# Request a permit
83+
# Request a permit via intent (LLM drafts the scoped-fetch spec)
6284
PERMIT=$(curl -s -X POST localhost:3737/permit \
6385
-H "Authorization: Bearer $AGENT" -H 'Content-Type: application/json' \
6486
-d '{
6587
"description": "List GitHub issues",
66-
"capabilities": [{
67-
"type": "scoped-fetch", "name": "github",
68-
"base_url": "https://api.github.com",
69-
"scope": ["/repos/OWNER/REPO/issues"],
70-
"auth": {"header":"Authorization","value":"Bearer {GITHUB_TOKEN}"}
88+
"intent": [{
89+
"name": "github",
90+
"goal": "List issues on owner/repo",
91+
"doc_urls": ["https://docs.github.com/en/rest/issues"],
92+
"secret_hints": ["GITHUB_TOKEN"]
7193
}]
7294
}')
7395
REQ_ID=$(echo $PERMIT | jq -r .request_id)
@@ -82,43 +104,24 @@ curl -s -X POST localhost:3737/approve/$REQ_ID \
82104
EXEC=$(curl -s -X POST localhost:3737/execute \
83105
-H "Authorization: Bearer $AGENT" -H 'Content-Type: application/json' \
84106
-d "{\"permit_id\":\"$PERMIT_ID\",\"action_id\":\"list-issues\",
85-
\"code\":\"const r = await github('GET','/repos/OWNER/REPO/issues'); console.log(JSON.stringify(r));\"}")
107+
\"code\":\"const r = await github('GET','/repos/owner/repo/issues'); console.log(JSON.stringify(r));\"}")
86108

87109
# Poll for result
88110
curl -s "localhost:3737/execute/$(echo $EXEC | jq -r .request_id)/status?wait=true" | jq .result
89111
```
90112

91-
## Deploy to a TEE
92-
93-
For production on [dstack](https://docs.phala.network/dstack/overview) (Phala CVM):
94-
95-
```bash
96-
cp dstack/.env.staging dstack/.env
97-
# Set: JWT_SECRET, ANTHROPIC_API_KEY, PG_PASSWORD, DOMAIN, CLOUDFLARE_API_TOKEN
98-
99-
docker build -t ghcr.io/YOU/oauth3-proxy:latest proxy/
100-
docker push ghcr.io/YOU/oauth3-proxy:latest
101-
# Pin digest (attestation requires exact match):
102-
docker inspect ghcr.io/YOU/oauth3-proxy:latest --format '{{index .RepoDigests 0}}'
103-
# Update dstack/docker-compose.yml with digest
104-
105-
phala deploy --cvm-id <UUID> -c dstack/docker-compose.yml -e dstack/.env
106-
```
107-
108-
The CVM runs: dstack-ingress (attested TLS via Cloudflare) → oauth3-proxy → postgres.
113+
See [DEPLOY.md](dstack/DEPLOY.md) for TEE deployment on dstack/Phala CVM.
109114

110115
## Project structure
111116

112117
```
113118
proxy/src/
114-
├── server.ts # HTTP API
119+
├── server.ts # HTTP API + intent drafting
115120
├── executor.ts # SES Compartment sandbox
116121
├── database.ts # SQLite (dev) / Postgres (prod)
117122
├── auth.ts # JWT with agent/owner roles
118123
└── plugins/
119-
├── scoped-fetch.ts # Main plugin: glob-scoped HTTP with rate limits
120-
├── cookie-session.ts
121-
└── tiktok-history.ts
124+
└── scoped-fetch.ts # URL globs, methods, body schema, rate limits
122125
dstack/
123126
├── docker-compose.yml # CVM deployment
124127
└── .env.staging # Env template

dstack/DEPLOY.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Deploy to a TEE
2+
3+
Production deployment on [dstack](https://docs.phala.network/dstack/overview) (Phala CVM):
4+
5+
```bash
6+
cp dstack/.env.staging dstack/.env
7+
# Set: JWT_SECRET, ANTHROPIC_API_KEY, PG_PASSWORD, DOMAIN, CLOUDFLARE_API_TOKEN
8+
9+
docker build -t ghcr.io/YOU/oauth3-proxy:latest proxy/
10+
docker push ghcr.io/YOU/oauth3-proxy:latest
11+
# Pin digest (attestation requires exact match):
12+
docker inspect ghcr.io/YOU/oauth3-proxy:latest --format '{{index .RepoDigests 0}}'
13+
# Update dstack/docker-compose.yml with digest
14+
15+
phala deploy --cvm-id <UUID> -c dstack/docker-compose.yml -e dstack/.env
16+
```
17+
18+
The CVM runs: dstack-ingress (attested TLS via Cloudflare) → oauth3-proxy → postgres.

0 commit comments

Comments
 (0)