Why we didn't use a blockchain: sealed-key custody and the issuer-identity problem
When you build a Verifiable Credential issuer, two questions arrive in the first week: “What chain are you putting credentials on?” and, when you answer “none,” a silence that expects a correction. We didn’t correct. The choice we made — sealed-key custody with a boot-guarded issuer boundary — wasn’t a rejection of blockchains as a class. It was a negative result: the problem people assume a chain solves is not the problem a credential actually has.
The honest negative result
The credentialing space defaults to “blockchain!” the way early web3 defaults to “token!” — a reflex that pre-empts the requirements analysis. Builders who have shipped issuers tend to be quieter about it. Partly that’s commercial caution; you don’t undermine a category that funders expect you to align with. Partly it’s that negative results are hard to publish — you’re explaining a non-choice, and non-choices don’t carry CVE numbers.
This is a non-choice we want on the record. We built the Mneurix Lattice LMS to issue credentials that carry real weight — AI-validated learning, assessment integrity, micro-credentials that downstream verifiers (employers, regulators, other institutions) can rely on. Early in the design we ran the blockchain option against the threat model and found it doesn’t address the dominant failure class. The failure class isn’t tampering. It’s impersonation.
This isn’t an anti-chain essay. Chains are useful for what they’re useful for. The problem is that “trust in a credential” is a phrase that compresses two distinct questions, and only one of them is a consensus question. The other is an identity-and-custody question. Consensus protocols have nothing to say about the second, and the second is the one that breaks credentialing systems.
Two trust questions, only one of which is interesting
A credential is, mechanically, a signed claim: issuer I asserts fact F about subject S at time T. Strip away the envelope formats — JWT, JSON-LD VC, the newer SD-JWT variants — and you’re left with a signature over a payload. A verifier checking that credential has exactly two trust questions:
- Tamper-evidence. Has the payload been altered since signing? Is the signature valid for the stated issuer key? Did signing happen at or before T?
- Issuer identity. Was the key that produced this signature actually the issuer’s key, in the sense that the issuer meant to issue this credential, under the issuer’s own control, free of compromise?
The first question is solved. It was solved before blockchains existed. Any append-only log plus a standard signature scheme gives you tamper-evidence; a signed JWT over a dated log entry is tamper-evident by construction. The cryptographic primitives — Ed25519, ECDSA over P-256, the newer BLS variants for aggregate use cases — are not the bottleneck. You do not need consensus ordering to prove that a signed payload hasn’t changed. The signature already does that work; the log just prevents replay ambiguity and ordering games. A git commit hash would serve.
The second question is the interesting one, and it’s where chain-based answers go quiet. A blockchain gives you consensus-ordered, tamper-evident events. It has no opinion on whether the thing that signed was the issuer or an attacker holding the issuer’s key. Consensus orders events; it does not authenticate the source of the signing operation. This is not a limitation anyone hides — it’s explicit in the architecture of every consensus protocol — but it’s the limitation that credentialing lives inside, because in credentialing the thing that breaks is almost never the ledger. It’s the key.
The Blockcerts impersonation pattern
The honest qualification here: the CVE timeline for “Blockcerts issuer impersonation” is thinner than the pattern itself. There isn’t a single, canonical advisory with a number you can cite the way you’d cite a buffer overflow in OpenSSL. What there is, instead, is a documented class of failure that’s been described in papers, in Blockcerts community threads, in post-mortems from issuers who got bitten — and a general architectural observation that anyone who reads the Blockcerts issuer-key mapping spec can make for themselves. I want to be honest about the evidence: this is a pattern, not a single event with a date.
Here’s the pattern. Blockcerts, like most on-chain credentialing systems, relies on an issuer identity anchored to a public key. The issuer publishes its key — typically by writing it into a Bitcoin transaction, or into a did:btcr-style resolution path — and verifiers check presented credentials against that key. So far, so standard.
The failure mode is that issuer-key mappings are, in practice, mutable and frequently reused. Issuers rotate keys, delegate signing to operational accounts, host their issuer profiles on infrastructure they don’t fully control. An attacker who obtains the issuer key — through compromise of the issuer’s signing service, through a mutable profile update, through a delegated account that was never revoked — can mint credentials that are, by every chain check, indistinguishable from genuine. The chain records them faithfully, in canonical order, immutably. Every verifier that checks the chain concludes genuine. Every verifier is wrong.
This is not a blockchain failure. It’s an issuer-identity and key-custody failure dressed up as a consensus success. The chain did exactly what it was designed to do: it prevented tampering and ordered events. The problem relocated — to wherever the key lives, which in credentialing is usually an issuer account on someone else’s infrastructure, accountable to nobody in particular. The chain didn’t eliminate the trust requirement; it moved it from “verify the ledger” to “trust the key holder,” and then proceeded to make “the key holder” invisible to the verifier. That’s a worse posture than having no chain at all, because it creates the impression that verification is complete when it’s not.
This is the central negative result. The chain option never removed the custody decision. It always still needed an answer to “who holds the issuer key, and under what conditions can it sign?” — it just made that question easier to skip. For a credentialing system where downstream trust is the product, skipping it is not acceptable.
Why sealed-key custody
The alternative we built is architecturally heavier and operationally explicit. That’s the point.
The issuer signing key in the Mneurix Lattice is sealed at rest — encrypted under a hardware-anchored key, unsealable only inside a measured-boot boundary. Unsealing requires that the running image hash matches the pinned, approved issuer image: the provenance of code and configuration is part of the unseal condition. The key never leaves that boundary in plaintext. Signing happens inside it; the signed credential leaves; the key does not.
Key rotation is explicit and, by design, breaks credentials issued under the previous key. That sounds like a bug; it’s a feature. If rotation is painless and silent, it’s invisible to verifiers and invisible to operators. If rotation breaks previously-issued credentials — or at minimum forces re-presentation under the new key with a visible revocation of the old — then you notice. You notice because downstream verifiers start asking why. Rotation that nobody notices is rotation that an attacker can also perform without anyone noticing. Visible rotation is a control; silent rotation is an attack surface.
Revocation is a first-class signed status list with a freshness SLA. Not an afterthought, not a sidecar, not “check the chain if you care.” Verifiers are expected to check revocation as part of verification, and the Lattice commits to publishing revocation updates within a bounded window. A credential without a fresh revocation check is not considered verified — this is the posture we document in the credentialing trust stack, and the reason we spent more engineering effort on revocation freshness than on anything chain-adjacent. A revocation list that might be stale by six hours is worse than no revocation at all — it gives the verifier false confidence that someone checked. The freshness SLA is the thing that makes the revocation root load-bearing, and no consensus layer gives you that for free. You have to build the publishing pipeline, monitor it, and break things visibly when it fails. That’s custody work, not protocol work.
Custody is a platform decision
This is the platform-economics point, and it’s the one most likely to get hand-waved. Custody is a platform decision, not a feature. When you choose sealed-key custody, you are choosing a trust posture: the issuer is a named, reachable, operationally responsible entity, and the key’s lifecycle is a first-class engineering concern with failure modes you own. When you choose “put it on a chain,” you are deferring that posture to whoever runs the nodes — and for credentialing, that’s nobody accountable. The chain’s validators have no contractual relationship to the credentials, no obligation to the issuers, no skin in the game if a key is compromised and the issuer goes dark. Decentralization without accountability isn’t trust; it’s distributed irresponsibility. We make this argument at length in the custodian problem, which argues that custody is the platform decision that owns the supply side — that whoever holds the issuer key is the platform, regardless of what ledger the credentials are written to. If you haven’t answered who holds the key and what happens when they fail, you haven’t shipped a credentialing system. You’ve shipped a hope.
Steelmanning the chain
Now let’s steelman the blockchain honestly, because the honest case is stronger than the strawman and still doesn’t get you there. A chain genuinely helps when you need a public, append-only, no-trusted-operator registry: land title in jurisdictions with corrupt recorders, supply-chain provenance where no single party is trusted to keep the books, timestamped attestation where the existence of a record at a point in time is the claim and no named issuer needs to revoke it later. These are real use cases. The chain gives you censorship-resistant ordering and a shared audit log that no single operator can rewrite. That’s a real property. It’s just not the property credential issuance needs.
Credential issuance requires a named, accountable, revocable issuer. The verifier needs to answer: who issued this, are they still authoritative, and is this credential still valid? The chain records the first faithfully. It cannot answer the second — the issuer’s continued authority is an out-of-band fact about the world, not a ledger entry. And the third, revocation, either requires the issuer to publish status updates to the chain (which means the issuer needs custody of a key that can write to the chain — back to square one) or requires an off-chain revocation registry (which is what we built anyway). The chain doesn’t eliminate the issuer; it just gives the issuer a more complicated place to write. For credentialing, where the trust claim is “this specific institution vouches for this specific person as of this specific time, and may withdraw that vouching,” the named-issuer requirement is not a limitation of current blockchain implementations. It’s structural. The issuer is the trust anchor; the chain is a notary. Notaries don’t replace principals.
The honest trade-off
Here’s the honest trade-off. Sealed custody means we are the trust anchor. That’s a heavier operational burden than “just use the chain,” and we want to be clear about that. We run the HSM or its equivalent. We maintain the boot-guard and image-signing supply chain that pins what runs in the boundary. We are the single point of failure if the sealed key is exfiltrated through a firmware compromise or a physical extraction. We own that risk. The residual risks are real: we are a central operator, and a sophisticated supply-chain attack on our signing infrastructure could forge credentials indistinguishable from our own. Boot-guard and image-signing narrow the attack surface, but they don’t eliminate it — they move the attack to the firmware signing key, which is also a custody problem. There is no custody solution that isn’t recursive; the question is where you choose to bottom out, and whether the entity at the bottom is one you can name, audit, and hold responsible. We chose us. We can name us.
The chain option, for all its surface appeal, never escaped this. It always still needed a custody decision for the issuer key. The issuer had to hold a key to write to the chain. That key had to live somewhere, be rotated or not, be revocable or not. “Just use the chain” was never the shortcut it was sold as — it deferred the same decision one layer down and made it less legible. The custody decision was always there, waiting.
This connects directly to our position on human review as advisory, not a blocker. Custody is the hard, revocable root — the thing that can actually withdraw a credential’s validity. Human review sits above it as a governance layer: it advises issuance, flags anomalies, and shapes policy. But it is not a replacement for custody, and custody is not a replacement for it. The two are stack layers. Human review without a custody root is opinion without force; custody without human review is mechanism without judgment. The mistake in both directions is collapsing one into the other. The blockchain reflex tends to collapse custody into protocol — assuming the chain’s mechanics substitute for the issuer’s authority. They don’t. They transport it, and sometimes not even that.
The custody decision is the one that matters
So here’s the honest coda. The blockchain reflex pre-empts the requirements analysis. You reach for the chain before you’ve asked what the trust claim actually is, who makes it, who can withdraw it, and what happens when they fail. By the time you’ve asked those questions, the chain is usually answering a different one. The negative result we want on the record is this: the custody decision is the one that matters, and no consensus protocol makes it for you. The key has to live somewhere. The entity that holds it is the trust anchor. The revocation path has to be fresh and owned. Everything else is plumbing, and the plumbing is solved. The custody decision isn’t, and it won’t be — not by a chain, not by a protocol, not by a clever cryptographic trick. It’s a platform decision, and we made ours.
Comments (Giscus) will appear here once the repo Discussions + giscus.app are configured.