US-first · not for profit · agentaccountability.us

Agent Accountability

Which company minted this agent, and can any gateway kill it. Not a tenant product. Not a central database of every agent.

  1. 01Company signsPrivate key stays home
  2. 02Agent presentsX-Agent-Credential
  3. 03Gateway checksPrefix, signature, expiry, revocation
  4. 04API or 403X-Agent-ID on pass

01 What this is

02 How a request works

  1. The issuing company signs a credential with its private key. The private key never leaves the company.
  2. The agent presents that credential in a header, X-Agent-Credential.
  3. The gateway checks prefix, signature, expiry, then that company’s revocation URL.
  4. Pass: forward the request and inject X-Agent-ID. Fail: 403.

03 Credential

A signed document. Change one field and the signature breaks. This is the same GRO credential the demo verifies.

credential.json

{
  "agent_id": "GRO-8CB7487B",
  "company": "GRO",
  "company_name": "Grok",
  "agent_name": "ResearchBot-7",
  "capabilities": ["web_search", "summarize"],
  "kid": "k2",
  "issued_at": 1791371562,
  "expires_at": 1793963562,
  "signature": "564f6874f12baf826debf2a2dd6776cf84086ab8a8a5eb7de530165527e46857f80fccb115158be6887b032edeec4a3bd7f720153ae7f7095e153d4aca035f0a"
}

04 Gateway

A reverse proxy in front of an API, DNS resolver, or control system. Stateless. No agent database. The URLs below are examples of the shape a company would publish. They are not live feeds.

agentid-gateway.yaml

# agentid-gateway.yaml
listen: ":8443"
upstream: "http://api.internal:8080"
mode: verify          # or reject_all

companies:
  OPI:
    public_key_file: "/etc/agentid/opi.ed25519.pub"
    revocation_url: "https://revocations.openai.com/v1/revoked.json"
  MUS:
    public_key_file: "/etc/agentid/mus.ed25519.pub"
    revocation_url: "https://crl.muse.ai/agents/revoked.json"
  BOT:
    public_key_file: "/etc/agentid/bot.ed25519.pub"
    revocation_url: "https://api.anthropic.com/agent-ids/revocations"
  GRO:
    public_key_file: "/etc/agentid/gro.ed25519.pub"
    revocation_url: "https://x.ai/agent-ids/revocation-list"

cache:
  revocation_ttl: "1h"
  reverify_list_signature: true

headers:
  credential: "X-Agent-Credential"
  identity: "X-Agent-ID"

05 Check order

  1. Prefix registered. Unknown prefix is rejected.
  2. Signature verifies against that company’s public key for this kid.
  3. Not expired.
  4. Revocation list pulled from that company’s URL. The list signature is rechecked on every use, including cache hits.
  5. Agent id not on the list.
Reject-all is a config, not a different product. Utilities and fintech that do not want agents set mode: reject_all. No credential, no access. Identified agents are blocked. Unidentified scripts are blocked too, same as requiring a badge at a door.

06 See it refuse

These credentials were signed for this proof. The page checks the Ed25519 signature in your browser against the sample public keys. Edit a field and the signature fails. The sample revocation list contains OPI-A770391F. The clock is the proof clock, so the expired sample still fails.

07 Sample gateway code

verify

def verify(self, credential: dict) -> tuple[bool, str]:
    code = credential.get("company")
    company = self.companies.get(code)
    if company is None:
        return False, "unknown company prefix"

    public_hex = company.keys.get(credential.get("kid"))
    if public_hex is None:
        return False, f"unknown key id {credential.get('kid')}"
    try:
        verify_ed25519(public_hex, credential)
    except Exception:
        return False, "bad signature"

    if time.time() > credential["expires_at"]:
        return False, "expired"

    rev, status = self.revocation_list(code)
    if rev is not None:
        try:
            self.check_revocation_list(rev)  # every use, including cache hits
        except Exception as exc:
            return False, f"revocation list invalid: {exc}"
        if credential["agent_id"] in rev["revoked_agents"]:
            return False, f"REVOKED via {code} endpoint ({rev['reason']})"

    return True, f"VALID (signed by key {credential['kid']}, revocations: {status})"

The only network call is the revocation fetch. Production is GET company.revocation_url. Air-gapped sites do not pull a public URL. They take a signed revocation bundle over their existing update channel. The browser demo uses a fixed sample list. It does not re-verify a signed list document, because this proof does not include one.

08 Revocation

09 Key rotation

10 Who does what

RoleOwnsDoes not own
Issuer (lab or platform) Signing keys, credentials, revocation URL The gateway, the prefix rules
Gateway operator Verification in front of their server Issuance, other companies’ keys
Project, later a neutral body Prefix registry and schema Keys, gateways, a database of agents

Nvidia is the natural builder of gateway software and hardware. Nvidia should not own the registry. A vendor running the rules is a conflict, and the labs will treat it as a sales channel.

11 Where it sits

12 Why a company resists

That resistance is the reason to do it. Banks, clouds, and regulated labs already get blamed. They want attribution. The rest want deniability.

13 Proof already run