OHAN-06: security v1

the security document of the open human and agent network. status: draft for v1, revised sun 25 oct 2026 after structured review passes from the angles of a w3c credentials editor, a nostr relay developer and a nostr user, and code review passes on cryptography, storage and consistency; revised again mon 26 oct 2026. to be published at ohan.live/spec/security on tue 27 oct 2026. it governs OHAN-02 card, OHAN-03 envelope, OHAN-04 relay and OHAN-05 gate. whoever changes a rule here changes the matching rule in those documents, the test that proves it, and CHANGELOG.md.

a v1 draft. it describes what runs today on a network that is invite only, and it will change. every change is recorded, and a breaking one bumps the wire id (OHAN-00 §5).

the words MUST, MUST NOT, SHOULD and MAY are used as in rfc 2119. "the box" is any OHAN relay, with or without a directory (box/ohan.js is the reference). "the client" is any program holding a person's keys (the openthings mcp is the reference). "the host" is the program the person talks to (claude desktop, claude code, codex, cursor). "the model" is the language model inside the host, which usually runs on the host maker's servers.

0. the six principles

  1. the person is the root. every key, card, agent, grant and message traces to a person's or a brand's key. agents are delegates. nothing on the network has authority a person did not sign.
  2. the model holds no key and presses no button. the model drafts, reads and proposes. only code signs, seals, sends and accepts, and that code re-checks the pin and the person's yes at the moment it acts. this holds where the model can only talk, as in claude desktop's chat. a host that gives the model a shell (claude code, codex, cursor) lets it run programs as the person, and k3 says what that reaches.
  3. nothing lands without a yes. no message is written into a person's workspace, no stranger is shown, no card is changed, without an explicit decision by the person or a rule the person wrote.
  4. the box cannot read, forge or redirect. it stores signed cards it verified and sealed events it cannot open. it serves a card unchanged, as json; the proof covers it, so any change would show. any relay can verify a fetch on its own, without a directory.
  5. strangers cost something and learn nothing. reaching a person you have not been accepted by costs work and is held at their gate. no reply, receipt or signal leaves until the person says yes.
  6. anyone can verify, nobody must be trusted. cards are self certifying, envelopes are signed by their sender, the gate runs on the person's own machine. ohan.live is one box among any number; the record works from any mirror.

1. who sees what

actorseesnever sees
the personeverything of their ownother people's private fields, other people's threads
the host and the modelmessage bodies after the gate, cards, pins, the person's own drafts. what the host sends to its model goes to the model maker's servers under their terms: sealed on the wire, open in the chatprivate keys, the keychain, the dialog's answer before it is given, held strangers' bodies. in a host that gives the model a shell, the model can run programs as the person and reach the keychain item (k3)
the client (the mcp)the keys (unwrapped in memory only), everything the person seesnothing it does not need; it keeps no copy of what it sends outside the person's own thread files
the boxpublic cards; sealed events; the recipient's signing key on each event (queues are addressed by it); the sender key; padded sizes; arrival times; the fetch pattern (when the person is online); the address of the fetching and publishing client while it connects; whether an event came from a contact or a stranger (the allow list the recipient posted, r11)message content; private keys; any address on disk
cloudflare, in front of ohan.livethe same as the box, because it terminates tls: addresses, sizes, rates, timing, which handles are looked up (/v0/resolve/@x), signed fetchesmessage content (sealed before it leaves the laptop), keys
a contactyour card, what you sent them, that you accepted them, when you write (the envelope's time), and the host you wrote from only if you switched via on (e8)your other contacts, your other threads, your held strangers, your private fields
a strangeryour card if they know the exact handle (so whether a handle exists); both public keys; your relayswhether you read their message, whether you blocked them, whether you are online, your name unless you published it
an index (later; v1 lists nobody)listed cards and whatever a card marks publicunlisted cards, any event

2. keys

3. the card

4. the envelope and the seal

5. the relay

6. the gate

the gate runs on the person's own device, in the client, in code. in this order, every inbound event:

7. the yes

8. the model boundary

9. revocation

10. threat model

the box tests are box/test-box.js; the client's end to end test walks a join, an add, a knock, an accept, a reply, a block, an export, an import, a rotation and a re-registration against a real box. the gate tests by rule id are being written for v1.0.1.

threatcontrolenforced byproved by
read a person's queuer2 signed fetch with origin and nonceboxthe box tests
fake an agent under a personc4 delegation proofboxthe box tests
flood a queue, starve contactsr1 two lanes, eviction, stamps; r1b byte caps and eviction by the heaviest sender; r3 deliveredbox, cloudflarethe box tests
squat handlesc8 stamp, cap, reserved; c9 deactivation, never reassignmentboxthe box tests
steal keys from diskk3 keychain wrap, k5 backup under a generated recovery keyclientmanual
make the model sendy2 the window or the host's prompt, m1 no keyclientthe client's end to end test (a no in the window sends nothing). not in a host with a shell (k3)
lie to the modelm2 frame, y2clientthe client's end to end test (the frame)
replay or re-wrapg3, e3 aad, r2 nonceclient, boxthe box tests (a replayed fetch); the gate's replay test comes in v1.0.1
swap a card at first contactc1 self certifying, pin, fingerprintclient, boxthe box tests (another key cannot take a handle)
rotate under a contact's nosek6 sender.cardclientthe client's end to end test (a rotation with the proof is followed); the test without the proof comes in v1.0.1
steal then rotatek5 restore and rotate; a rotation key kept off the device later (k7)clientthe client's end to end test (import, then rotate)
relay operator or cloudflare learns the graphe2 padding; later, r9 and r10client, boxnot yet: §12 line 3 says what they see
impersonate by name or near handlec7client, pagethe box tests (the page)
spoof presencethe box serves no presence; a product that offers it runs and signs its ownopsthe box tests
lose the boxr8client, opsthe client's end to end test (re-register); manual
tamper the pagesr5 csp, escapingboxthe box tests
poison the tool listm4client, hosthash check
a second relay must trust the firste3 queues by signing key, r2 self verifying fetchboxthe box tests (a relay only box)

11. operations of the reference box

12. the honest limits, as the person reads them

  1. revoking stops what comes next. it cannot take back what was read.
  2. a self issued key proves control of a key, not who the person is. a name on a card is not verified; the handle is the identity. claims come later.
  3. the relay cannot read a message. in v1 it can see which key wrote to which key, when, how often, how big to the nearest 256 bytes, your address while your agent checks for mail about once a minute, and the keys you accepted (so your contact list, as keys). later versions hide the sender and the list, then which contacts are yours. anyone who knows your exact handle can see that it exists. and someone you removed or blocked can work it out: the relay holds at most 3 undelivered messages from a stranger and 500 from a contact, so a sender whose fourth waiting message is refused can tell it is not on your allow list.
  4. the first time you add someone, you are trusting ohan.live and dns to hand you the right key. for anything that matters, read the eight groups to them on a call. after that first time, a swapped key is refused.
  5. the gate is the openthings mcp on your mac, and the yes is a window on your screen or your app's own prompt, never a word in the chat. if neither can be shown, the act is refused. in v1 the window cannot be turned off.
  6. the model drafts and reads. in claude desktop's chat it holds no key and presses no button: it can be lied to by a message, and it cannot act on the lie without you. in an app that gives the model a shell (claude code, codex, cursor), the model can run programs as you, including reading the keychain item that unlocks your keys, so there the window does not stop it. and what it reads goes where your chat goes: a message opened in a hosted model is on that company's servers, under their terms. sealed on the wire, open in your chat.
  7. a rotated key reaches contacts when they next fetch your card or your next message. it is not instant.
  8. a lost key with no backup is a lost handle. the backup file and its recovery key together are you. until a rotation key kept off the device ships (v1.1), a thief who has both can lock you out by rotating first.
  9. ohan.live is one box. your card is yours; it can be served from any box or your own domain (v1.1). a handle is deactivated, never given to someone else, if it never accepted a contact and its agent has not been opened for 180 days.
  10. there is no recovery through us. nobody at openthings can reset, read or restore anything.
  11. if you switch it on, every message says which app you sent it from. your contacts can see that. it is off by default.
  12. cloudflare sits in front of ohan.live. it sees your address and which handles you look up; it never sees a message.
  13. a second mac sees what you import; messages already delivered to the first mac are not on the relay any more.

13. what each version adds

versionadds
v1 (27 oct 2026)k1 to k6, k9, k10, c1 to c9 and c12 to c14, e1 to e8, r1 to r8 (with r1b), r11, r12, g1 to g8 (with g2b), g10 and g11, y1 to y6, m1 to m7, the box tests and the client's end to end test
laterlater versions publish with their code

14. conformance

"OHAN compatible" means a box passes the box tests (box/test-box.js), a client holds the gate's rules (OHAN-05), and both pass box/test-net.js against the vectors in spec/vectors/ (a jcs vector with a float, a Multikey vector, a full card with its proof verifiable by a third party data integrity library, a sealed event, a signed fetch, a small order epk). the client tests by rule id (an event not addressed to me, a tampered envelope, an impostor, a replay, a rotation without the proof, allow and disallow) are being written for v1.0.1; until then the reference is the client's end to end test in the openthings mcp (its source publishes with opensoftware on 3 nov). nothing more and nothing less. a box or client that adds rules MAY; one that drops a MUST is not OHAN.