Skip to content

fix(claim): reuse sealed at-rest token after a check-in nulls its hash#125

Merged
Jolah1 merged 1 commit into
mainfrom
fix/door-a-heir-lockout-token-reuse
Jun 19, 2026
Merged

fix(claim): reuse sealed at-rest token after a check-in nulls its hash#125
Jolah1 merged 1 commit into
mainfrom
fix/door-a-heir-lockout-token-reuse

Conversation

@Jolah1

@Jolah1 Jolah1 commented Jun 19, 2026

Copy link
Copy Markdown
Owner

Critical: Door A heirs were locked out of claims

A Door A (password-vault) heir was permanently locked out of any claim once the owner had checked in at least once before lapsing. Owners check in constantly by design (it's a dead-man's switch), so in practice this hit almost every real Door A inheritance.

This is pre-existing (predates the non-custodial track / #124) and is live on mainnet. The signet e2e surfaced it.

Root cause

  • The check-in handler nulls claim_token_hash (so a fresh alarm starts clean) but never clears claim_token_at_rest_b64.
  • The trigger's reuse logic keyed on both fields being present, so a checked-in password vault fell through to minting a brand-new token.
  • The heir's xprv is sealed under the original token via HKDF — a fresh token can never unseal it. The fresh token is also base64url, which crashed the claim page with a cryptic atob error before the heir even got that far.

Fix

  • scheduler: decide reuse on the sealed at-rest token alone. Decrypt it, reuse that exact token, and re-derive + write back the hash when a check-in had cleared it. Legacy vaults (no at-rest token) still mint fresh — unchanged.
  • sealing: make b64decode tolerant of base64url so a valid token can never crash the claim with atob again.

Tests

  • cargo test -p ghostkey-server — 137 passed (+1: password_vault_reuses_at_rest_token_after_checkin_cleared_hash, reproduces check-in → lapse → claim)
  • web vitestsealing.test.ts, base64 / base64url round-trips

Notes

  • No migration needed; existing rows self-heal at trigger.
  • The current signet test vault can't be recovered (its heir key was sealed under a token the server already discarded); a fresh vault validates the fix end to end.

🤖 Generated with Claude Code

@vercel

vercel Bot commented Jun 19, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
ghost-key Ready Ready Preview, Comment Jun 19, 2026 11:10am

A Door A (password-vault) heir was permanently locked out of any claim
once the owner had checked in at least once before lapsing.

Root cause: the check-in handler nulls `claim_token_hash` (so a fresh
alarm can start clean) but never clears `claim_token_at_rest_b64`. The
trigger's reuse logic keyed on BOTH fields being present, so a checked-in
password vault fell through to minting a brand-new token. The heir's xprv
is sealed under the ORIGINAL token via HKDF, so the fresh token can never
unseal it. The new token is also base64url, which crashed the claim page
with a cryptic `atob` error before the heir even got that far.

Owners check in constantly by design (it's a dead-man's switch), so in
practice this hit almost every real Door A inheritance. Pre-existing
(predates the non-custodial track); surfaced by the signet e2e.

Fix:
- scheduler: decide reuse on the sealed at-rest token alone. Decrypt it,
  reuse that exact token, and re-derive + write back the hash when a
  check-in had cleared it. Legacy vaults (no at-rest token) still mint.
- sealing: make b64decode tolerant of base64url so a valid token can
  never crash the claim with atob again.

Tests:
- scheduler: password_vault_reuses_at_rest_token_after_checkin_cleared_hash
- web: sealing.test.ts (base64 / base64url round-trips)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@Jolah1
Jolah1 force-pushed the fix/door-a-heir-lockout-token-reuse branch from b83ef28 to 5e8ba72 Compare June 19, 2026 11:09
@Jolah1
Jolah1 merged commit 9b1f42f into main Jun 19, 2026
8 checks passed
@Jolah1
Jolah1 deleted the fix/door-a-heir-lockout-token-reuse branch June 19, 2026 11:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant