Security model

The gate enforces; the human decides; the agent can neither reach the console nor change the policy.

Pre-release. lockhttp v0.2.0 is out as a pre-release and runs in Docker only (one lockhttp launcher, a cosign-signed image): command names are fixed, flags may still move. TLS decryption ships in it and is optional, wired by lea: without a local CA and the signer (--ca-cert, --signer), HTTPS is decided at the domain. Design decisions: docs/decisions.md, contract with lea: docs/lea.md.

Non-negotiable requirements

  • Console in its own container

    Under its own account (lockhttp), the only container with the policy volume. The agent gets neither its socket nor the Docker socket.

  • NeverAuto by default

    Only an approved auto rule, scoped to a container, can be answered by auto mode, and the console re-checks the rule against its own approved policy first.

  • Identical fingerprint

    One human decision covers only requests with the same container, method, URL, significant headers and normalised body.

  • Claude API allowlist

    Once TLS is decrypted, mcp_servers, server tools other than web_search, files and foreign credentials never pass without a human.

  • Fail closed

    No console, an unknown source, an unreadable source map, a policy that does not decode: ASK is refused, errors deny.

Threats and answers

Assets: the project’s and the host’s data, credentials, and actions taken online in your name. Attackers: the agent itself (prompt injection, drift) and hostile web content. Out of scope: a compromised host, Anthropic, a network attacker upstream.

ThreatAnswerWhat remains
Going around the proxyAgents sit on internal networks; squid listens on loopback; the gate refuses its egress interface.Rootless Podman without an isolated gateway: covered by a blocking isolation test in lea.
DNS, DoH, IP literalsNon-forwarding DNS in lea; the network floor; no UDP.IP literals of declared internal hosts.
Writing to a trusted hostA write asks, even on a trusted host.Without decryption the gate sees only the host; the screen says “reads and writes”.
Exfiltration in a GETDecryption, and the exfiltration score (logged in shadow by default; heuristics = "enforce" asks).Slow, low-bandwidth channels; spliced hosts.
The Claude API as a relayPath and parameter allowlist (with decryption).Without decryption, the exact host only.
Approval fatigueAuto rules you approved; identical requests grouped; shadow mode to tune first.The human factor.
The agent edits the policyThe policy lives with the console; loosening needs your review; project files are ignored.—
A compromised gateOwn uid, never root; no decision authority over ASK; the CA key in a separate signer.FREE traffic.
Agent impersonationRules apply to containers, never to agents; the agent name is audit only.Attribution between agents of one container.
Prompt injection through the screenTerminal sanitising; the agent’s stated intent is marked untrusted.—
No consoleASK refused at once; FREE on the last approved policy.Reduced availability, on purpose.

Audit

The gate writes FREE and DENY to a daily JSONL file, kept 30 days; the console writes every ASK to its audit log. Both carry the same request_id, the container, the declared agent and how it was attributed. The audit never holds a body or a secret.

The container is known for sure (one internal network per container). The agent is an attribution, not an authentication: agents of one container share a uid.

Report a vulnerability

Please do not open a public issue. Report it privately as described in SECURITY.md (a private GitHub security advisory).