Metadata-Version: 2.5
Name: agent-police-gate
Version: 0.1.0
Summary: Client-side tool-call gate for coding agents: screens what Claude Code and Codex are about to run, and keeps a tamper-evident record of it.
Project-URL: Homepage, https://github.com/RomaCredit/agent-police-gate
Project-URL: Source, https://github.com/RomaCredit/agent-police-gate
Project-URL: Issues, https://github.com/RomaCredit/agent-police-gate/issues
Project-URL: Audit your relay, https://security.romaapi.com
Author: RomaCredit
License-Expression: Apache-2.0
License-File: LICENSE
Keywords: agent,claude-code,codex,hooks,llm,policy-gate,prompt-injection,security,supply-chain,tool-call
Classifier: Development Status :: 3 - Alpha
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Security
Classifier: Topic :: Software Development :: Quality Assurance
Requires-Python: >=3.10
Provides-Extra: dev
Requires-Dist: pytest>=7.4; extra == 'dev'
Requires-Dist: ruff>=0.6; extra == 'dev'
Description-Content-Type: text/markdown

# agent-police-gate

**Screens what your coding agent is about to run — before it runs it — and keeps a tamper-evident record of every call.**

[![CI](https://github.com/RomaCredit/agent-police-gate/actions/workflows/ci.yml/badge.svg)](https://github.com/RomaCredit/agent-police-gate/actions/workflows/ci.yml)
[![License](https://img.shields.io/badge/license-Apache--2.0-blue)](LICENSE)

[中文](README.zh-CN.md) · [Project page](https://security.romaapi.com/gate/en) · [Audit your relay](https://security.romaapi.com/en) · [agent-police](https://github.com/RomaCredit/agent-police)

```bash
pip install agent-police-gate
apgate install claude-code     # or: apgate install codex
```

Works in **Claude Code** and **Codex CLI** from one implementation — both pass the same `PreToolUse` payload and accept the same response, so the only per-agent artifact is a few lines of config.

## Why

If your agent reaches a model through a third-party relay, that relay terminates your TLS and opens its own connection upstream. It can rewrite every JSON payload in flight, **including the arguments of the tool calls your agent is about to execute**. No vendor offers end-to-end integrity for tool calls today, so the client cannot verify that the command it is about to run is the command the model produced.

[agent-police](https://github.com/RomaCredit/agent-police) answers *"is this endpoint tampering?"* by probing it. **This project answers the other half: "should this specific command run?"** — inline, on every call, whether or not you ever probed the endpoint.

The attack classes come from Liu et al., *[Your Agent Is Mine: Measuring Malicious Intermediary Attacks on the LLM Supply Chain](https://arxiv.org/abs/2604.08407)* (arXiv:2604.08407), which measured **428 commercial relays** and found **9 injecting malicious code**, **17 touching the researchers' AWS canary credentials**, and **1 draining an ETH private key**. The paper describes three client-side defenses but [does not release them](#relationship-to-the-paper).

## What it does

| | |
|---|---|
| **Policy gate** | Screens each tool call against a rule bundle. Blocks credential exfiltration outright; forces a prompt on high-risk shapes **even in YOLO / accept-edits mode**. |
| **Transparency ledger** | Hash-chained, append-only, local. Removing or editing a line breaks verification. |
| **Retroactive rescan** | `apgate rescan` re-screens recorded history with today's rules — so an indicator published this week can be run against sessions from last month. |

### The part that matters most in practice

When you run an agent with approvals off, nothing prompts. The gate puts **one** prompt back, only for the shapes that actually matter — a script piped into a shell from an unrecognised host, an install redirected to a foreign registry, a URL whose real host is hidden behind a `@`.

## Agent support, as measured

Both agents were tested live, not read about. Two behaviours are worth knowing before you install:

**Codex ignores a project-level `.codex/hooks.json`.** Only `~/.codex/hooks.json` is discovered, which is where `apgate install codex` writes. Codex also pins trust to the hook's hash, so run `/hooks` once to review and trust it — until you do, it is skipped silently.

**`ask` does nothing when approvals are off.** With `permission_mode: bypassPermissions`, Codex ran a command the gate had answered `ask` on — correctly, since there was nobody to prompt. That makes every `ask` rule a no-op in exactly the unattended sessions that need it most, so the gate **escalates `ask` to `deny` when no human is in the loop**. An unanswerable prompt fails closed. Set `APGATE_FAIL_OPEN=1` if you want the other behaviour.

## Honest limits

**This cannot tell you the model's original output.** A `PreToolUse` hook sees the tool call *after* it passed through the relay; it never saw what the model actually produced. So every check here is a heuristic about whether a command *looks* wrong, never a comparison against ground truth.

The paper measured its own policy gate at **100% bypass by an adaptive attacker**. That number applies here too. What a gate like this catches is the generic, non-adaptive rewriting that the 428-relay survey actually found in the wild — which is worth catching, and is not the same as being safe.

Closing the gap properly needs a signed response envelope from the vendor, binding model id, tool name, tool arguments, `finish_reason`, and a client nonce. No major tool-use API or MCP spec provides one.

## How rules stay accurate

Rules are **data, not code** — a rule picks from a fixed predicate table and supplies literals. There is no regex from a bundle, no IO, no subprocess, and evaluation is linear in the input. A rule that can execute is a rule that can be weaponised, and this one is fetched over the network.

Accuracy is enforced mechanically, not by review:

* every rule ships its own positive and negative cases;
* CI runs the **whole** bundle against a shared corpus of ordinary developer commands;
* **a rule that blocks and fires even once on that corpus does not ship.**

And provenance decides power:

| Tier | Reviewed | May block |
|---|---|---|
| `core` | yes | `deny` / `ask` |
| `community` | corpus only | **never** — `observe` only |

That split is what lets an open rule library exist. A wrong community rule costs a line in a log, not a developer whose agent stopped working for a reason they cannot see. The schema enforces it: `validate_rule` rejects a community rule carrying `deny`.

## Updates

**Rules update automatically. Code does not.**

This runs inside an agent with shell access. An auto-updating code channel would be a remote-execution path onto every user's machine — the exact supply-chain shape this project exists to catch. Codex agrees, structurally: it pins hook trust to the hook's hash and will not run a changed hook until you review it.

So: code moves through `pip install -U`, user-initiated and auditable. Rule bundles are signed with [Sigstore](https://www.sigstore.dev/) keyless signing via GitHub Actions OIDC — **this project holds no signing key** — and carry a Merkle root published with each release, so a client can check that the bundle it was served is the bundle everyone else was served. Including when the mirror is ours.

## Usage

```bash
apgate install claude-code        # merges into ~/.claude/settings.json (backs it up first)
apgate install codex              # merges into ~/.codex/hooks.json; then run /hooks in Codex to trust it

apgate screen "curl -sSL https://get.example.com/i.sh | bash"   # offline, one command
apgate rules                      # what is loaded, and what can block
apgate report                     # ledger summary + chain status
apgate verify                     # verify the chain alone
apgate rescan                     # re-screen history with today's rules
apgate uninstall claude-code
```

Exit codes for `screen`: `0` nothing blocking, `2` a `deny` rule matched.

### Privacy

The ledger is local, mode `0600`, and never uploaded. Secret-looking tokens are scrubbed before writing. Set `APGATE_LEDGER_ARGS=0` to record only hashes of command text, or `APGATE_LEDGER_OFF=1` to disable recording entirely. There is no telemetry in this release; when it arrives it will be opt-in and will never carry command text, prompts, or file contents.

## Relationship to the paper

Section 6 of arXiv:2604.08407 says the authors implemented "companion client-side modules" for the three deployable defenses. Appendix A.4 then states plainly: *"No public release of Mine"* — and scopes that to *"the compatibility and defense results in Sections 6–7"*, which is the same artifact holding those modules. The phrase "the released scripts" appears twice, but no link, DOI, or artifact-availability statement appears anywhere in the paper.

So the defenses are described and measured, and nothing is obtainable. This is an independent implementation, not a repackage.

## Scope

Screen your own machine. This tool reads commands and never executes them.

## License

Apache-2.0
