Engineering notes

The Agent Passport: design and threat model.

This is how the credential at the center of Veryl actually works, written for the engineer or security reviewer who will be asked to check our claims. Everything here describes the behavior of the system as built, and the specification is versioned so you can hold us to it when the beta opens.

Why a credential

The trust an agent earns is useless if it can't leave the building.

An agent that passes verification inside one system is trusted only by that system. The moment it is exported, sold, or shared with a partner organization, the question returns: says who? Our answer is a portable credential. The Agent Passport states what an agent is, what it can reach, what verification it passed, and when that claim expires, in a form anyone can check without calling us to ask.

That last property is the design constraint that shaped everything else. A credential you must phone the issuer to interpret is a login, not a passport.

The format

Boring on purpose.

A passport is a JWS in compact serialization, signed with Ed25519. We chose the most conservative primitives we could:

  • One algorithm, ever. Verifiers reject anything but EdDSA over Ed25519. No negotiation means no downgrade.
  • The wire bytes are the canonical bytes. The payload is JSON with sorted keys and no whitespace; the signature covers exactly the bytes you received. There is no separate canonicalization layer to disagree with itself.
  • Keys are public and cacheable. Verification keys are published as OKP JWKs at a well-known JWKS URL, cacheable for an hour, so verification works offline from a cached key set.
  • Rotation never orphans a passport. Rotating the signer demotes the old key from signing but keeps it published, so everything it signed keeps verifying. Retiring a key, reserved for suspected compromise, is what invalidates its signatures.
prior-auth-navigator.passport.jws
{
  "agent_version_id": "ver_a41f9c02",
  "identity":     { "name": "Prior-Auth Navigator", … },
  "capability":   { "model_tier": "standard",
                    "tools": […], "mcp_connectors": […] },
  "content_hash": "sha256:a41f…9c02",
  "verification": { "status": "verified",
                    "report_hash": "sha256:77d3…",
                    "expires_at": "2026-10-10" },
  "lineage":      { "version_num": 32, … }
}
header         alg EdDSA · typ JWT · kid ed25519-…
signature      ed25519 ✓ verifies against /.well-known/jwks.json

Abridged for reading. Field names and semantics are normative in the specification.

The threat model

Each claim, and what attacks it.

A credential is only as good as the attacks it was designed against. These are the ones that shaped the Passport, and the mechanism that answers each.

Forged passports

Answered by the signature itself. Ed25519 over the exact wire bytes, verified against published keys. A verifier also cross-checks that the envelope around a passport agrees with the signed payload, and the signed payload always wins.

Tampering after verification

The passport commits to a content hash: SHA-256 over the canonical form of the version's material fields, its instructions, guardrails, tools, model tier, knowledge sources, and response schema. Any material change is a new hash, which is a new version, which owes a new verification. A trusted version that receives a material edit drops out of its trusted state automatically.

Stale trust

Every verification carries an enforced expiry: 90 days when self-attested, 180 when an independent reviewer signed off. A passport without an expiry is treated as invalid by design, and a lapsed agent reports itself not invocable and will not run until it passes again.

Revocation that outruns the signature

Signatures cannot express "we changed our minds this morning," so the passport pairs with a live status endpoint. Quarantining a version revokes every export credential for it in the same database transaction, and the runtime re-reads the authoritative state inside the invocation transaction immediately before any model call. A quarantine that lands mid-request still blocks the request.

Signing-key compromise

Private keys are envelope-encrypted at rest: each key sealed under a fresh data key with AES-256-GCM, data keys sealed under a versioned master key. Suspected compromise means retiring the key, which removes it from the published key set and invalidates its signatures, while routine rotation stays cheap and non-disruptive.

Rewriting history

Every state change, export, and invocation lands in a per-organization, append-only hash chain keyed with HMAC-SHA256. Chain heads are serialized so concurrent writes cannot fork history, and chain verification is exposed as an endpoint you can call, not a promise you have to take.

Cross-tenant probing

Passport and credential reads are organization-scoped, and a cross-tenant miss returns 404, never 403. Whether something exists is itself information, and we don't leak it.

Stolen export credentials

Export keys are bearer secrets and treated with appropriate suspicion: stored only as argon2id hashes, shown exactly once at creation, pinned to a single agent version, individually revocable, optionally expiring, and rate-limited. Where a surface needs to know who the person is, it uses OAuth 2.1 with per-user consent instead of a shared key.

Having to trust the verifier

The verification procedure is three checks anyone can run: signature against public keys, expiry against the clock, status against a public endpoint. A standalone verifier package implements exactly this procedure with no dependency on our service, so "trust us" is never the answer.

What we don't claim

The honest edges.

Security documents that only list strengths are marketing. These are the boundaries of the current design, stated plainly.

A passport attests the past, not the future

It proves what was verified, when, and against what configuration. It does not prove the agent will behave tomorrow. That is what expiry, re-verification, live status, and the audit trail exist for, and why all four are mandatory parts of the design rather than features.

API keys are bearer credentials

Whoever holds the string can use it until it is revoked or expires. We contain that with hashing, single display, version pinning, revocation, and rate limits, and we push surfaces toward OAuth where person-level identity matters. We do not pretend a key is an identity.

Humans drive trust decisions

Automated checks advise; a named reviewer decides, and the author of a version may not approve their own work. This is slower than full automation and we consider that a feature at this stage, not a limitation to engineer away quietly.

Tamper-evident is not tamper-proof

The audit chain proves whether history was altered; database-level append-only grants are what prevent alteration, and environments can require that enforcement at startup. We say tamper-evident on purpose, and our formal audit status is stated plainly on the security page.

Read the specification.

The Agent Passport wire format, manifest fields, verification procedure, and status contract are written up as a versioned specification. It moves to a public repository when the Registry beta opens; until then, ask and we send the current draft. A standard is only a standard if you can check it.