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
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
- Project: `/home/avi/Projects/0_Nostr`
- Git repo: `master` @ `4461307` ("Create vault files owner-only from the first byte").
Before it: `4bd7660` (legacy vault perms), `4d4dfde` (CSP + navigation guards),
`6e627a3` (upload pick tokens), `4bde395` (IPC allowlist), on top of contact-aware
feed (`a1445d1`) etc.
- Git repo: `master` @ `130d7e2` ("Zeroize transient secret key material in memory").
Before it: `4461307` (owner-only writes), `4bd7660` (legacy vault perms), `4d4dfde`
(CSP + navigation guards), `6e627a3` (upload pick tokens), `4bde395` (IPC allowlist).
- 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.
@ -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.
- 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
- `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).
- `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.
@ -122,12 +137,13 @@ Manual protocol checks worth doing once:
## 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`,
decrypted hex strings in `crypto.rs`/`profiles.rs`).
2. Smaller: link-preview SSRF guard (block loopback/private IPs), signer pending-cap,
NIP-46 secret echo check, backend request timeout.
1. Link-preview SSRF guard — block loopback/private IPs in `fetchLinkPreview` (`main.ts`).
2. Signer pending-cap — bound the approval queue (e.g. max 10) against relay spam.
3. NIP-46 secret echo check — verify the client echoes the handshake `secret`.
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,
#3 CSP + navigation, #4 legacy vault perms, #5 write-race windows).
All six primary findings are closed (#1 IPC allowlist, #2 upload tokens, #3 CSP +
navigation, #4 legacy vault perms, #5 write-race windows, #6 zeroization).