Malte Buttjer · 11 February 2025

Possession is the password

A concept for a zero-knowledge emergency medical ID on a physical tag: readable by any stranger at the scene, unreadable by everyone in between

The decryption key travels on the tag itself, so the server only ever holds ciphertext. What follows is the whole design: how several tags share one record, why keys never rotate, and the four limits the spec states out loud.

  1. 01

    The emergency

    A crash, a seizure, a fall. A stranger finds you unresponsive.

  2. 02

    The scan

    A tag on the helmet, bracelet or keyring. Any phone; no app, no account.

  3. 03

    The decrypt

    The key rides in the URL fragment; plaintext appears only in their browser.

  4. 04

    The response

    Allergies, medication, contacts, labeled in the finder's language.

Someone finds you unconscious. Maybe you came off your bike on a forest road; maybe it was a seizure in a supermarket queue, a diabetic collapse at a bus stop, or the fall your eighty-year-old father insists will never happen on his daily walk. On the helmet, the bracelet, the keyring, there’s a tag with a QR code; the stranger scans it with whatever phone they carry, and gets your allergies, your medication, your emergency contacts, labeled in their language, because a Danish tourist may be the one kneeling next to you.

For that to work, the tag has to be readable by absolutely anyone. No app, no account, no permission dialog. That is the entire point of an ICE tag, and any design that compromises it has failed before it starts.

The idea took shape during my years at Tocsen, building crash sensors for bike helmets. Spend that long thinking about the minutes after a crash (riders, helmets, first responders) and emergency information becomes a subject you can’t put down. What should the person kneeling next to you be able to learn, and how? I kept returning to it long after, and the longer I looked, the less it was about sport at all: the same minutes follow a stroke, an allergic shock, a fall in old age. And every architecture I sketched ran into the same wall.

The wall: a medical profile is about the most sensitive data a person has, and some of it, like allergies and chronic conditions, can never be changed once leaked. The tension between maximally readable at the scene and disclosed to nobody else is the whole problem. What follows is the design I arrived at. It currently exists as a specification; more on that at the end.

The promise problem

The existing answers resolve the tension with terms of service. Commercial medical-ID platforms store your profile in plaintext in their database, behind a login and a privacy policy. Which is fine, right up until the breach, the acquisition, the subpoena, or the quarter where monetizing “anonymized health insights” starts looking reasonable.

For data you cannot rotate (you can change a password, not an allergy), I think the bar is simple: “will not read it” is not good enough. The operator must be unable to read it. Not because operators are villains, but because “unable” survives everything “unwilling” doesn’t: the operator’s worst employee, their best hacker, their acquirer, and their government.

That’s the constraint everything here starts from: the server only ever stores ciphertext. Whoever runs it (a company, a cycling club, me) cannot read anyone’s medical data. Not by policy. By construction.

A key you can print

The mechanism is almost disappointingly old. A URL has a fragment, the part after the #, and browsers never transmit it. It’s resolved entirely client-side. Firefox Send and PrivateBin built on exactly this behavior; this design puts it on a sticker:

https://tag.example/t/4taFEsU6Kh1PW9#Bq7mzXo91WcRfK3TduA

Path: sent to the server

A random 128-bit lookup handle. Grants nothing: not read, not write. Server logs, proxies and browser history only ever see this part.

Fragment: never sent

Browsers strip everything after # before a request leaves the device. The key exists in two places: printed on the tag, and in the scanning browser’s memory.

Note what a tag actually is: nothing but that URL. So the carrier is a free choice. A printed QR sticker, an NFC chip that opens on tap, an engraving on a bracelet you type in by hand; anything that can convey a short line of text is a valid tag, and they can all point at the same record. The reading side is equally unassuming: the phone’s camera or NFC reader hands the URL to the browser, and the browser does the rest. No app to install, at either end, ever.

The profile is encrypted on the owner’s device (AES-256-GCM, client-side, always) and the server stores the ciphertext. The key is carried by the tag itself, in the fragment. Scanning the tag loads a static viewer page, which fetches the ciphertext and decrypts it in the browser. The key’s entire life is spent on the physical tag and, briefly, in the scanning device’s memory.

Follow what this does to the trust map. The server can’t read profiles; it never sees a key. Anyone who can read server logs, proxy logs, or a browser history can’t either: paths carry a random lookup handle with zero capability. There are no accounts, so there are no passwords to phish, reset flows to hijack, or credential dumps to join. The physical tag is the capability. Possession is the password, which is the access model an emergency demands: the person who can help you is defined by being there, next to the tag, and so is authorized by the same fact.

One secret, many doors

One tag is a keychain with one key. Real life needs more: a helmet sticker, a bracelet, a card in the wallet, a chip on the walker, and the ability to lose any one of them without losing everything.

So underneath there’s a small key hierarchy. Each record has a random master key that exists only client-side. Two working keys are derived from it with HKDF, one that encrypts and one that authorizes writes, and each physical tag carries its own independent key, which wraps the master key; the wrapped blob is what the server stores. The server also stores a hash of the write key, so it can verify edits without being able to make them meaningful: it could scribble in its own database, but it can never produce ciphertext that decrypts, and clients treat undecryptable data as tampering, loudly, never as “profile empty”.

Three consequences fall out of that structure, and they’re the product:

  • Losing a tag is survivable. Revoking it is a single authorized delete of its wrapped key on the server. The lost tag goes dead everywhere, your other tags don’t notice, and, crucially, nothing carried on any tag ever changes. Engraved bracelets, factory-written NFC chips and pre-printed sticker sheets all just keep working.
  • Editing requires exactly what reading requires. The write key derives from the master key the tag already unwraps. Scan your own tag, edit, done. No login, because there’s nothing to log into.
  • A database breach is a non-event for confidentiality. The attacker gets ciphertext, wrapped keys they can’t unwrap, and a hash with a 256-bit-entropy preimage. There is no offline attack to run.

An earlier iteration of this design had a flaw worth naming: knowing a URL path allowed destructive writes, so every proxy log was a loaded gun. The current design closes that twice over. Path knowledge grants nothing, and even a hypothetical rogue write couldn’t destroy anything, because versions are append-only: vandalism by someone holding a stolen tag is bounded to appending garbage, and any other tag or the recovery kit can restore the history and revoke the thief. On this record, nothing is ever lost by accident, and nothing is kept against the owner’s will either: erasure and revocation are hard deletes.

Maintenance is a failure mode

Here’s a constraint security people underrate: an emergency system must work precisely when it hasn’t been thought about for three years. A fire extinguisher that needs a monthly login would be a fire hazard. Whatever security schemes usually assume (rotation schedules, re-authentication, an email you still control), an ICE tag on a kayak helmet or an eighty-year-old’s bracelet can’t. The people who need one most are the people least likely to maintain an account for it.

So the design inverts the usual hygiene: keys never rotate on a schedule. Nothing expires, nothing needs refreshing, no service ever has to reach you. Key generations exist, but they increment only on suspected compromise. And recovery is a piece of paper: a printed kit with the master key as a checksummed code, in text and QR. It works with zero configured services. Email recovery exists as an optional adapter, and the spec is blunt about its rank: email may re-deliver convenience, never capability. An inbox alone must never yield key material, because inboxes are exactly the thing that gets taken over.

Trading secrecy, visibly

Sometimes an emergency legitimately needs more than a scan at the scene: a dispatcher, an event medic, a care platform watching over an elderly parent, a crash-detection app that wants to forward your profile the moment it fires. The tempting answer is an API key with read access, and it quietly reintroduces everything the design just removed.

The answer here is the break-glass share: a snapshot of fields you select, encrypted under its own throwaway key, living behind its own fragment-carrying link, with a hard TTL of at most 30 days and guaranteed deletion at expiry. Integrating apps get a token that can create shares. It can never read records or touch tags. The framing from the spec is the part I’d defend anywhere: when an emergency needs plaintext-equivalent access, confidentiality is traded deliberately, visibly, and temporarily, instead of silently and permanently. Most privacy failures in practice aren’t broken crypto; they’re silent, unbounded grants that nobody remembers issuing. Making the trade explicit and self-destructing is the ethical core of the design, applied at the one place secrecy genuinely has to bend.

The field

This space isn’t empty, and the neighbors deserve a fair reading. The most interesting one is Twiceme, the helmet industry’s emerging “digital safety standard”: an NFC chip embedded at the factory (Smith, Kellys, Simpson and others ship it), holding your medical profile directly on the chip. Their availability story is genuinely excellent, and honestly better than mine: there is no server, so there is nothing to be down. The trade, as I write this, is everything else. The chip’s content is plaintext for any phone tap: the finder at the scene, but equally the helmet thief and the buyer of your used gear. Updating means physically re-writing every item you own, one tap at a time. And a lost helmet cannot be deactivated from afar: whatever it knew, it keeps announcing.

  • Engraved band / paper card

    Data at rest:
    Plaintext on the object
    Updating:
    Make a new object
    If it's lost:
    Disclosed; nothing to revoke
    At the scene:
    Works offline, always
  • Twiceme (chip in the gear)

    Data at rest:
    Plaintext on the NFC chip; any phone tap reads it
    Updating:
    Physically re-tap each item of gear
    If it's lost:
    Disclosed; the chip stays readable forever
    At the scene:
    Works offline; no server exists
  • Hosted QR profiles

    Data at rest:
    Plaintext in the vendor's database
    Updating:
    Remote, instant
    If it's lost:
    Revocable via your account
    At the scene:
    Needs the vendor's server, which can also read everything
  • Phone lock-screen Medical ID

    Data at rest:
    Plaintext on the phone
    Updating:
    Instant, on the phone
    If it's lost:
    Remote wipe, but the phone was the carrier
    At the scene:
    Offline, if the phone is present, intact and charged
  • This design

    Data at rest:
    Ciphertext; the key is printed on the tag. The operator cannot read it
    Updating:
    Remote, from any tag
    If it's lost:
    Revoke that one tag; the others don't notice
    At the scene:
    Needs a server to be up (see limits)

Every row of that table is a design picking which failure it can live with. Engraving picks permanence, Twiceme picks offline availability, hosted platforms pick convenience and pay in trust. This design picks remote control and an operator who cannot read, and pays for it elsewhere.

What it doesn’t defend

The threat model opens with a sentence I’ll hold myself to: a privacy product that hides its limits is not one. So, the limits.

  • The code-delivery problem. The server that stores only ciphertext also serves the JavaScript that decrypts it; a malicious or coerced operator could serve poisoned code. Every web-delivered E2E system carries this asterisk: Proton and Bitwarden’s web vault carry it today; Firefox Send did. The responses are staged: say it plainly in the docs, then shrink it with reproducible builds, signed releases, update pinning, eventually a native verifier. And self-hosting collapses the trusted set to “a server you run yourself”, which for this project’s audience is rather the point.
  • A lost tag is a disclosed profile. Whoever physically holds your tag can read it. That’s by design, since readable-by-strangers is the product. Revoking it helps from that moment on; whatever was already read stays read. No cryptography fixes this; the UI has to say it instead.
  • Availability is not guaranteed. An emergency read needs the server up. This is an information carrier, not a medical device, and no protocol makes a hosting bill into an SLA. The fallback is paper: the docs recommend printing an offline card for your wallet, plaintext, next to the recovery kit.
  • Metadata is minimized, not hidden. The server learns that a record exists, when it changes, and from which IPs. Documented so a self-hoster can judge, not waved away.

Every one of these could be blurred with marketing. Refusing to is a feature in the same sense the encryption is: the user’s mental model of the system is part of the system.

Where it stands

What exists today is a specification: the protocol, a threat model with twelve binding security requirements, and known-answer test vectors any implementation must reproduce byte-for-byte. The crypto code is deliberately unwritten: implementation is gated on at least one independent cryptographic review of the spec, because in cryptography, enthusiasm is how you ship vulnerabilities. Spec-first also keeps a subtler promise: with the contract normative and the vectors published, every implementation is checkable, including a future one that isn’t mine.

The engineering posture follows the threat model into the build system: zero runtime dependencies, WebCrypto only, a vanilla client with no framework and no CDN, because for a zero-knowledge product, every dependency is audited attack surface, and a viewer page that must work on a trailhead’s one bar of 2G had better be tiny anyway. One small codebase, deployable to a serverless edge, a container, or a bare VPS, because self-hostable has to mean actually easy to host.

As for where this should end up: this shouldn’t be a product you subscribe to. It should be infrastructure, the way smoke detectors are. A sports club runs a server for its members without becoming a custodian of medical data, because it can’t read any. A helmet maker embeds tags at the factory under a batch ceremony that keeps no copy of any key. A care service hands out bracelets it cannot read to people it looks after. A family runs one instance for the grandparents on a five-euro VPS. Emergency information on helmets, bracelets, keyrings and walkers, unremarkable, and no plaintext database of anyone’s medical life sitting anywhere, waiting.

The spec is the deliverable right now, and it’s looking for adversaries. If you can break it, I want to hear from you.