Skip to content

security: close key-escrow, AAD-binding, and KDF-downgrade gaps#63

Merged
SoulNaturalist merged 1 commit intomainfrom
claude/password-manager-security-checklist-8EMX6
Apr 28, 2026
Merged

security: close key-escrow, AAD-binding, and KDF-downgrade gaps#63
SoulNaturalist merged 1 commit intomainfrom
claude/password-manager-security-checklist-8EMX6

Conversation

@SoulNaturalist
Copy link
Copy Markdown
Owner

Round 2 of the security audit, focused on architectural / E2E / malicious-backend threats from the 2026 ETH research checklist.

CRITICAL

  • Server-side seed-phrase encryption (key escrow / recovery bypass) removed. /profile/seed-phrase now rejects plaintext bodies outright and refuses to server-decrypt legacy blobs (returns 409 with a re-enrol hint). EncryptionService class deleted from server/utils.py so no code path can reach SEED_PHRASE_KEY any more.

HIGH

  • AES-GCM ciphertexts in the vault now bind to per-record context via AAD ("payload:<site_hash>" / "meta:<site_hash>" / "notes:<site_hash>"). A v2: prefix tags new-format blobs; legacy v1 blobs continue to decrypt with empty AAD for backwards compatibility. Refusing to decrypt v2 without a context throws — no silent downgrade. This closes the malicious-backend row-swap attack: any swap by the server pairs a ciphertext with a different site_hash than the one that authenticated it, and GCM tag verification fails.

MEDIUM

  • Client now enforces a hard floor of 100 000 PBKDF2 iterations (CryptoService.minAcceptableKdfIterations). A malicious server can no longer downgrade a registering client to a trivially brute-able iteration count. The legacy floor was chosen so existing accounts keep unlocking; new registrations get 600 000.

Also:

  • Account-level seed phrase moved to the bound 'account-seed' AAD namespace (cryptographic domain separation from per-record blobs).
  • decryptNotesSecure helper added so notes use their own AAD context.
  • All call-sites (passwords_screen, password_detail_screen, edit_password_screen) thread site_hash through to the decrypt methods.

See docs/SECURITY_AUDIT.md "Round 2" for the full report including the items reviewed and confirmed safe (sharing flow, emergency access, metadata leakage budget) and follow-up work for public-key share auth.

https://claude.ai/code/session_01TnnbXj4NqgHqALLwbHP2nq

Round 2 of the security audit, focused on architectural / E2E /
malicious-backend threats from the 2026 ETH research checklist.

CRITICAL
  * Server-side seed-phrase encryption (key escrow / recovery bypass)
    removed. /profile/seed-phrase now rejects plaintext bodies outright
    and refuses to server-decrypt legacy blobs (returns 409 with a
    re-enrol hint). EncryptionService class deleted from server/utils.py
    so no code path can reach SEED_PHRASE_KEY any more.

HIGH
  * AES-GCM ciphertexts in the vault now bind to per-record context via
    AAD ("payload:<site_hash>" / "meta:<site_hash>" / "notes:<site_hash>").
    A v2: prefix tags new-format blobs; legacy v1 blobs continue to
    decrypt with empty AAD for backwards compatibility. Refusing to
    decrypt v2 without a context throws — no silent downgrade. This
    closes the malicious-backend row-swap attack: any swap by the server
    pairs a ciphertext with a different site_hash than the one that
    authenticated it, and GCM tag verification fails.

MEDIUM
  * Client now enforces a hard floor of 100 000 PBKDF2 iterations
    (CryptoService.minAcceptableKdfIterations). A malicious server can
    no longer downgrade a registering client to a trivially brute-able
    iteration count. The legacy floor was chosen so existing accounts
    keep unlocking; new registrations get 600 000.

Also:
  * Account-level seed phrase moved to the bound 'account-seed' AAD
    namespace (cryptographic domain separation from per-record blobs).
  * decryptNotesSecure helper added so notes use their own AAD context.
  * All call-sites (passwords_screen, password_detail_screen,
    edit_password_screen) thread site_hash through to the decrypt
    methods.

See docs/SECURITY_AUDIT.md "Round 2" for the full report including the
items reviewed and confirmed safe (sharing flow, emergency access,
metadata leakage budget) and follow-up work for public-key share auth.

https://claude.ai/code/session_01TnnbXj4NqgHqALLwbHP2nq
@SoulNaturalist SoulNaturalist merged commit 1912ee3 into main Apr 28, 2026
3 checks passed
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.

2 participants