What the protocol requires by design#
- Fail closed. The protocol specifies that an unknown, missing, ambiguous or unavailable input produces
DENY, neverALLOW. The engine implements every check in a fixed order and the first failure is the reason. - Nothing to trust but signatures. A Grant is signed by the company with a key in its DID document; a Proof is signed by the agent and bound to one recipient, one action and one moment; the receipt is signed by Delegus Check. Every link is a signature or a domain proof.
- Receipts are evidence. Each receipt pins the hashes of the Grant, the request, the company's DID document and the revocation list as they stood, and the profile applied. Anyone holding a receipt can confirm it is genuine without calling Delegus, and its parties can check what it pins (spec §6, §8).
- Revocation is read-after-write.
/revokereturns success only once every later/verify, on any node, will see it (spec §7). - The verify path is narrow.
/verifytouches only the database and the cache. No DID resolution, DNS lookup or third-party call happens while a decision is being made (spec §5.5).
How the service is run#
| Area | Control |
|---|---|
| Signing keys | Ed25519 keys in Google Cloud KMS, which can't be exported. Receipts and status lists are signed inside KMS, so private key material never enters a process. The API signs in to Google with short-lived credentials and stores no cloud key. It can sign and read public keys, but it has no permission to destroy a key, and every key is set so that a destroy request waits 120 days before anything happens. Rotation adds a new key id. Keys are never removed from the DID document: the earlier keys receipt-1 and status-1 are retired and no longer used for signing, and they stay published so every receipt they signed still verifies. |
| Evidence | Every artifact a receipt references is stored by hash in write-once storage: a private Backblaze B2 bucket, encrypted at rest, with Object Lock in compliance mode and a seven-year retention that can't be shortened once written. Evidence stored before we moved to this storage on 4 November 2026 was copied over and checked by hash. |
| Data in transit | The API uses TLS for every connection: from callers to the API, and from the API to the database, the cache and the evidence store. |
| Secrets | Service secrets live in the hosting provider's environment settings, set from our infrastructure code. The API is designed not to write secrets to its logs. API keys are shown once at issue, stored hashed, and can be rotated and revoked by their holder; a revoked key stops working immediately. |
| Deployment | Images are built by GitHub Actions on each change to the main branch. A production release happens only when the reviewed infrastructure code names a new image, or by a deliberate manual deploy; nothing deploys on its own. Each release must pass a health check before it takes traffic, and a release that fails it never serves a request. |
| Edge | The API enforces its own limits per key and per IP and answers 429 with Retry-After. A web application firewall in front of the API is planned. |
| Audit trail | The API keeps an append-only audit log of onboarding, key, agent, Grant and revocation actions with the actor, target and request id, readable by administrators in full and by each company or relying party for its own actions (GET /audit). Every request carries a request id, returned to the caller. Receipts themselves are a signed record of every authorization decision. Google Cloud records every administrative change to the signing keys, such as creating a key or changing who may use it. |
| Monitoring | Development and production are checked from outside, and their health is shown on a public status page. Alerts on error rates, and on any attempt to tamper with a signing key or the evidence store, are planned. |
| Isolation | Development and production run as separate services with separate databases, caches, evidence buckets and signing keys, and each environment's service can reach only its own keys. Development identifiers use did:web:dev.delegus.ai; nothing issued there is a production artifact. |
The specification's threat model (§13) is mapped threat by threat to the check, the code path and the test that addresses it in the threat model mapping.
Reporting a vulnerability#
Write to hello@delegus.ai with the subject "Security", saying what you found and how to reproduce it. We acknowledge within two business days. Please test in the free sandbox in your account, not against anyone else's data.