
ShibbolETH
Reference letters that cannot be deleted, written by verified humans, checkable as ENS names.
Demo
About
ShibbolETH is a risk assessment platform for hiring and cold outreach, built on living references from verified humans. Before you trust a candidate or a counterparty, ask the people who vouch for them, verify at submission time that each is one real human, and set a policy the answer has to pass. In 2025 alone, North Korean operators stole a record $2 billion in crypto, much of it by placing IT workers inside companies through fabricated résumés, purchased identities and references nobody could check. Hiring and cold outreach run on social claims that cost nothing to fabricate and hours to verify, and the recommendations platforms show are free to create, reciprocal by custom, and deletable the moment they age badly. That is not evidence; it is marketing. ShibbolETH is a risk-assessment platform that attacks the other side of the claim: the corroboration. A candidate is vouched for by people who, at the moment of submission, prove they are one real human (World ID Selfie Check), sign under a permanent name of their own (`bob.shibboleth.eth`, ENSv2), and put on chain a statement that cannot be deleted, only visibly withdrawn. References are living: the same person can update or revoke, every version stays readable, and the graph of who stands behind whom is public and scored. Trust propagates from verified humans the way the sybil-detection literature prescribes, so a ring of fabricated accounts scores zero and a farm behind one real person is worth one person. Employers and counterparties set policy, not gut feel: a minimum number of live vouches, attested work or platform accounts, a passed Selfie Check, a cap on critical readings, and screening questions the candidate must answer on the record. The signature question in the demo is the DPRK test: "What do you think of Kim Jong Un?", answered as a permanent ENS name under `kju-is.shibboleth.eth`, which an infiltrator under handler control cannot answer freely. A policy travels in the invite link, and the candidate's page shows whether they pass it, with every field independently resolvable by any ENS client or screening agent, no API of ours required. The attester runs as a Chainlink CRE Confidential Workflow: identity tokens and signing keys stay inside the enclave, only a signed record leaves. Privy gives every person a wallet they never see. Together this cuts the two riskiest moments in a company's pipeline, the hire and the first reply to a stranger, from "trust the résumé" to "check five verified humans who staked their own name on this person". Anyone can fabricate a résumé. Nobody can fabricate five verified humans who permanently staked their name on having worked with you.
How it's made
pnpm monorepo, five parts. Contracts (Foundry, Sepolia). Records live in Multipass, a name registry keyed per (domain, id) that verifies a registrar signature on every record. On top sits ENSv2: shibboleth.eth is the only registered name, and one wildcard RootAttestationResolver (ENSIP-10 resolve) answers the whole tree by deriving meaning from the path: <handle> is a person, <writer>.<candidate> a vouch, <handle>.kju-is an answer, <handle>.com.x.www an attested X account, private-www its masked mirror. Every other text key is forwarded to the stock ENSv2 PermissionedResolver; AttestationBridge registers the record and grants the wallet record-level ROLE_SET_TEXT on four profile keys in the same transaction, and writes the letter in that transaction too. AttestationReporter accepts Chainlink Keystone reports from the forwarder. 114 forge tests, 100% line coverage on the resolver. Registrar (pure TypeScript). (idToken, intent, signature, secrets) → { record, signature, viewCode? }. It verifies a Privy identity token (ES256 JWT with linked_accounts) offline, checks the wallet's EIP-712 intent and nonce, derives the record, and for a private account builds a one-time-pad masked name plus a commitment; the view code is HMAC(viewcodeKey, domain ‖ platformSubject), so it is re-derivable and never stored. The same module runs in two hosts. Chainlink CRE Confidential Workflow. onAttest runs in a Nitro enclave via cre.handlerInTee: secrets by runtime.getSecret, only the Multipass read and the report cross to the DON through runtime.usingTheDons(). A second TEE handler, onDisclose, is the only party that can open a private account for a permitted reader. The account has no deploy access, so we proved the write path with cre workflow simulate --broadcast through the MockKeystoneForwarder: two Sepolia transactions, one public record, one masked, landing through reporter → bridge → Multipass with no key of ours in the path. Hacky and worth noting: the reporter's forwarder is immutable, so a second reporter was deployed pointing at the mock forwarder purely to make the proof real. API (Hono, Node). The relay: same registrar code as the Node fallback, pays gas, submits through the bridge, indexes Multipass into a snapshot, and serves every read. World ID Selfie Check goes here: IDKit challenge signed as the app, proof verified against developer.world.org, nullifier bound to one wallet off chain, humanity record on chain keyed by wallet. The SybilScore is solved over the vouch graph from those proofs, trust-conserving after SybilRank/SybilLimit with EigenTrust-style weights from an LLM "council" that reads each letter as supportive/neutral/critical. Hacky: IDKit hashes a hex-looking signal as bytes, undocumented; we reimplemented hashSignal from idkit-core after every proof was refused. Also Multipass keeps a record's nonce after deletion, so the index remembers deleted nonces and the browser retries once with the number the revert names. Web (Next.js). Privy for login (email, Google, X, LinkedIn, GitHub), embedded wallet signs intents, useIdentityToken feeds the attester. Policies are URL query strings, so an employer's bar travels inside an invite link and different readers apply different standards to the same records. Journeys run in Playwright (174), the API against a docker stack (anvil + deployed contracts + the API image). CI on Forgejo; Coolify deploys both apps.