Skip to content
↑↓ to move · Enter to openEsc to close
Release notes · security · integrity · release notes

Removing fabricated verification from our own codebase

Shipped · commits 80672ca, 1a52a2c, ea3ff9b

A verification protocol is worth exactly as much as the claim that its outcomes are computed. This post describes code in AgenID's own repository that asserted verification outcomes without computing any, what replaced it, and the tests that now make the standard build-breaking rather than a matter of review.

We are writing it up because the standard AgenID asks of others, that a verified state be produced by evidence and never by default, has to be the standard it holds itself to. The project's own record counts seven instances of fabricated verification claims reaching the repository, one of which shipped to production for a day.

What was found

The largest instance was generated code: a command-line tool and three API routes that returned verification outcomes without computing them.

  • One route returned ORGANIZATION_VERIFIED for any domain submitted to it.
  • A DNS token was hard-coded, identical for every user and every domain.
  • Server-side key storage silently wrote operator keys as plain hex whenever its encryption secret was unset.
  • A public onboarding page had every operator sign a fixed operator name, contact, purpose, and both disclosure attestations (discloses_to_user, human_escalation) preset to true, under their own key.
  • DECLARED, which sits below L1, rendered in Verified Emerald with confetti.

What replaced it

The stubs were replaced with real Ed25519 paths that report DECLARED and nothing above it. The command-line tool now generates real keys, builds manifests from explicit operator attestations, signs a ManifestProof over RFC 8785 canonical bytes, writes the private key with 0600 permissions and never prints it.

Server-side operator key generation was deleted outright rather than hardened, so the registry never holds an operator private key. The onboarding page now collects the operator's own identity and attestations instead of signing fixed ones. DECLARED renders amber, and the panel states plainly that no third party has checked the claims.

Smaller claims that were also untrue

Dead and out-of-namespace hosts were removed from public copy. Endpoints that were not deployed, the second key-discovery path and the assertion write path at the time, were labelled as not deployed in the docs, the homepage diagram and every Verification Card's instructions. A privacy escrow feature described on the site did not exist and was removed. The root package guard that prevents publishing the whole monorepo by accident was restored.

Making the standard a test

packages/web/test/public-surface.test.ts turns each of these into a build-breaking assertion. A later sweep found two more defaulted attestations, registration implemented twice, and the presentation layer deciding trust state, which led to the fail-closed presentation change. The rule it all comes down to is simple: a level, a badge or a sentence may claim only what was computed from evidence.

The same rule sets the ceiling every AgenID page states. The reference deployment at agenid.com issues nothing above L1_REGISTERED today: L2 and higher require a VerificationAssertion signed by a root authority key, and that key has not been created yet. L5 is reserved and is not issuable at all.

What it means for operators and verifiers

For operators, the lesson is to sign only what you mean: at /issue the behavioral attestations start false and must be set deliberately. For verifiers, the lesson is the protocol's own design: do not take a displayed level on faith. Resolve the envelope and re-verify it, as described in how to verify an AI agent. Which agent is acting is not the same question as what it is allowed to do. AgenID answers the first. Protocol v1.1.1 defines no signed authorization object, so permission stays with the operator and with the party on the other side.

Frequently asked questions

Did any agent receive a real level above L1 because of these stubs?

No level above L1 can be signed, because no root authority key exists. The stubs asserted outcomes in responses and on screen; they could not produce a valid signed assertion.

How do I know the current code computes what it reports?

You do not have to trust it. The envelope carries signatures you can re-verify offline, and the registry cannot forge an operator signature.

Why publish this at all?

Because a verification protocol that hides its own integrity failures is asking for a trust it has not earned. The fixes and the tests are the useful part.

What agenid.com issues today

The reference deployment at agenid.com issues DECLARED and L1_REGISTERED only. L2_DOMAIN_VERIFIED and higher require a VerificationAssertion signed by a root authority key, and that key has not been created yet. L5 is reserved by the specification and is not issuable at all.

Identity is not permission

Which agent is acting and who declared it is one question. What that agent is allowed to do is another, and it stays with the party on the other side and with the operator. Protocol v1.1.1 defines no signed authorization object.

Give your agent an identity

Register an agent in the browser — the signing key is generated on your device and never sent to AgenID — or resolve an existing AgenID and re-check its signature yourself.