Refresh checkpoint with key zeroization

This commit is contained in:
Avi 2026-08-21 15:31:03 -05:00
commit d90b6e53d4

View file

@ -1,4 +1,4 @@
# Checkpoint — Owner-only-from-first-byte file writes (2026-08-21) # Checkpoint — Key material zeroization (2026-08-21)
A stopping point you can return to if this session is closed. Everything below was A stopping point you can return to if this session is closed. Everything below was
verified green at the moment this file was written. verified green at the moment this file was written.
@ -6,13 +6,12 @@ verified green at the moment this file was written.
## Where things are ## Where things are
- Project: `/home/avi/Projects/0_Nostr` - Project: `/home/avi/Projects/0_Nostr`
- Git repo: `master` @ `4461307` ("Create vault files owner-only from the first byte"). - Git repo: `master` @ `130d7e2` ("Zeroize transient secret key material in memory").
Before it: `4bd7660` (legacy vault perms), `4d4dfde` (CSP + navigation guards), Before it: `4461307` (owner-only writes), `4bd7660` (legacy vault perms), `4d4dfde`
`6e627a3` (upload pick tokens), `4bde395` (IPC allowlist), on top of contact-aware (CSP + navigation guards), `6e627a3` (upload pick tokens), `4bde395` (IPC allowlist).
feed (`a1445d1`) etc.
- Working tree is **clean** apart from this checkpoint update, which is committed right after. - Working tree is **clean** apart from this checkpoint update, which is committed right after.
## What was completed: security hardening items #1#5 ## What was completed: security hardening items #1#6
Fixes from the 2026-08-21 security audit. Fixes from the 2026-08-21 security audit.
@ -80,8 +79,24 @@ page could read+publish arbitrary local files to nostr.build. Now:
with a manual open-at-0600 + `io::copy`, making backups owner-only from their first byte. with a manual open-at-0600 + `io::copy`, making backups owner-only from their first byte.
- New test: backup of a 0664 source comes out 0600 with identical content. - New test: backup of a 0664 source comes out 0600 with identical content.
**#6 Key material zeroization (`130d7e2`, adds `zeroize = "1"`):**
Decrypted secrets and derived keys no longer linger in unscrubbed heap memory:
- `crypto.rs`: `decrypt_secret` returns `Zeroizing<String>` (self-shredding on drop); the
UTF-8 error path wipes the raw bytes too; a failed Argon2 derivation wipes its key buffer.
- `profiles.rs`: `resolve_secret_key` / `resolve_active_secret_key` now return
`Zeroizing<String>`, so every transient plaintext key flowing to publish/upload/signer is
wiped when its scope ends. Newly generated keys in `create_profile` are wrapped the same
way. `reveal_secret_key` still hands a display copy to the UI by design.
- `app.rs`: `lock()` and a new `Drop for App` zeroize the session vault key; wrong-password
derivations wipe their throwaway keys; password change wipes the previous vault key and
the old unlock key; `remove_password` moves decrypted values into storage via
`std::mem::take` without extra copies (plaintext-at-rest is that feature's purpose).
- Callers in `publish.rs`, `uploads.rs`, `signer.rs` needed no changes (deref coercion).
## Commits ## Commits
- `130d7e2` "Zeroize transient secret key material in memory" — Cargo.toml, crypto.rs,
profiles.rs, app.rs (+77/23).
- `4461307` "Create vault files owner-only from the first byte" — src/vault.rs (+48/2). - `4461307` "Create vault files owner-only from the first byte" — src/vault.rs (+48/2).
- `4bd7660` "Tighten permissions on leftover legacy vault files" — src/vault.rs (+79/3). - `4bd7660` "Tighten permissions on leftover legacy vault files" — src/vault.rs (+79/3).
- `4d4dfde` "Enforce header-based CSP and block window open/navigation" — main.ts + index.html. - `4d4dfde` "Enforce header-based CSP and block window open/navigation" — main.ts + index.html.
@ -122,12 +137,13 @@ Manual protocol checks worth doing once:
## Outstanding / next steps (if you continue) ## Outstanding / next steps (if you continue)
Remaining audit items in priority order: Remaining smaller hardening items from the audit:
1. **Zeroize** — wipe decrypted key material via the `zeroize` crate (`VaultKey`, 1. Link-preview SSRF guard — block loopback/private IPs in `fetchLinkPreview` (`main.ts`).
decrypted hex strings in `crypto.rs`/`profiles.rs`). 2. Signer pending-cap — bound the approval queue (e.g. max 10) against relay spam.
2. Smaller: link-preview SSRF guard (block loopback/private IPs), signer pending-cap, 3. NIP-46 secret echo check — verify the client echoes the handshake `secret`.
NIP-46 secret echo check, backend request timeout. 4. Backend request timeout — `backendRequest` in `main.ts` has no timeout; hung backend
leaks pending promises.
All five medium findings from the audit are closed (#1 IPC allowlist, #2 upload tokens, All six primary findings are closed (#1 IPC allowlist, #2 upload tokens, #3 CSP +
#3 CSP + navigation, #4 legacy vault perms, #5 write-race windows). navigation, #4 legacy vault perms, #5 write-race windows, #6 zeroization).