Fix revoke-rebinds bug; correct the website's custody and revoke claims

The audit's most important finding was not a doc issue at all. In
vaultSetBinding the identifier `origin` resolved to the WORKER GLOBAL
self.origin rather than the intended value, so the dashboard's "Revoke
app access" REBOUND the record to the calling page instead of clearing
it -- the precise cross-origin adoption the binding guard exists to
prevent, wearing the label of the button meant to prevent it. It
typechecked because the DOM lib declares that global. I introduced this
hours ago: a string replace intended for one call site silently matched
two. Fixed, with the reasoning written where the next reader will hit it.

Relay/account audit fixes:
- Phrase recovery permanently tripped the rollback alarm. The mark is
  keyed by the everyday pubkey (unchanged by recovery) while recovery
  legitimately restarts at generation 0, and raiseHighWaterMark keeps
  the maximum -- so anyone who had ever rotated a password met "possibly
  revoked credentials" on EVERY later login, forever, with no way to
  clear it. The phrase is the master authority; it now resets the mark.
- quorumMet counted TCP connections, not answers: a query timeout
  RESOLVED, so a connectable-but-silent relay counted as responding and
  every "not enough relays answered" guard was near-vacuous. Only EOSE
  is an answer now.
- Relay responses were never checked against the address requested, so
  one junk event from one relay blocked registration, rotation, and
  recovery for every login name and password a user tried. Events must
  now match author, kind, and d-tag.

Website honesty (the surface a stranger reads first, and the one that
had drifted furthest from the spec):
- docs.html and llms.txt still carried "private keys never leave the
  worker" -- false on its face, since the widget ships a reveal-nsec
  button. Both now state the same limit the README does.
- "you revoke" became honest everywhere: removing a connection deletes
  the stored copy; spending authority is revoked at the wallet.
- index.html dropped a pre-softening recovery claim, now says an account
  lives only while relays retain its capsule, and says "independently
  unaudited" out loud.
- llms.txt gains the two warnings that were missing entirely: losing
  BOTH password and phrase is permanent, and removal is not revocation.
- Stale headers: nwc-connections.md no longer claims "Not implemented",
  docs/README no longer says the authorization layer is unbuilt, the
  test count and spec version are current, and the demo domain points
  at bitlogin.network.

Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01CMr9Yt8SYmZcfgrg3CV2G1
This commit is contained in:
thePR0M3TH3ANandClaude Fable 5 committed 2026-07-31 09:47:01 -04:00
1 parent d040c2f5af
commit efd994c4de
11 files changed
+129 -30

No files matched your search

+4 -2
View File
@@ -36,8 +36,10 @@ identity and recovery model.
The Connection Vault stores portable application credentials outside the core
identity capsules as independently encrypted records. Its protocol layer
(records, key hierarchy, relay sync, migration, tiers) is **implemented in
`@bitlogin/core`'s `src/vault/`**; the widget authorization layer (consent
UI, grants, Connected apps) is still to come.
`@bitlogin/core`'s `src/vault/`**; the widget authorization layer shipped 2026-07-30 in REVEAL mode
(`requestNwcConnection`, `offerNwcConnection`, and a Wallet-connections
screen). Durable per-origin grants and a Connected-apps page are still to
come; see `connection-vault.md` §19 for the open limitations.
- [`connection-vault.md`](./connection-vault.md) — overall vault architecture,
key hierarchy, relay storage, authorization, recovery, and deletion; §18
+5 -1
View File
@@ -3,7 +3,11 @@
**Status:** Experimental design
**Document version:** 0.1
**Date:** July 22, 2026
**Implementation status:** Not implemented
**Implementation status:** PARTIALLY implemented. The parser/exporter and the
canonical credential shipped in `packages/core/src/vault/nwc.ts`, and the
request/offer flows shipped in the widget. NOT implemented: declared
capabilities, budget and expiry fields, `get_info` refresh, the suspend state,
broker mode, and the `wallet.*` API in §12 — those sections remain design.
## 1. Summary