Files
relicario/docs/superpowers/audits/2026-05-01-security-audit-opus-4-5.md
adlee-was-taken 71d51c0bea docs: add security audits and Plan 4 for blocker fixes
- 2026-04-18 initial audit verification (all fixed except H8)
- 2026-05-01 audit with 8 new findings (B1-B4, I1-I6)
- Plan 4: Security Blocker Fixes implementation plan

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-02 00:42:17 -04:00

4.6 KiB

Verification: 2026-05-01 Security Audit

Verified by: Claude Opus 4.5
Date: 2026-05-01
Methodology: Code inspection of referenced file paths and line numbers


Summary

Finding File Exists Lines Accurate Vulnerability Real Confidence
1 - Backup KDF NFC 10/10
2 - Commit injection 10/10
3 - WASM private key exposure 10/10
4 - Test env vars in prod 10/10
5 - AttachmentId 64-bit ⚠️ off-by-1 9/10
6 - Field history plaintext 10/10
7 - Device keys non-functional 10/10
8 - Path traversal restore 10/10

Verdict: All 8 findings are verified as real vulnerabilities in the current codebase.


Finding-by-Finding Verification

Finding 1 — Backup KDF missing NFC normalization

  • File: crates/relicario-core/src/backup.rs
  • Claimed lines: 303-312
  • Verified: derive_backup_key at lines 303-312 passes passphrase directly to argon.hash_password_into() without NFC normalization. Compare to derive_master_key in crypto.rs:224-227 which explicitly normalizes.
  • Impact confirmed: Cross-platform restore failure for non-ASCII passphrases.

Finding 2 — Commit message injection via item titles

  • File: crates/relicario-cli/src/main.rs
  • Claimed lines: 565, 899-901, 1110, 1327
  • Verified:
    • Line 565: format!("add: {} ({})", item.title, item.id.as_str())
    • Line 1110: format!("edit: {} ({})", item.title, item.id.as_str())
    • Line 1327: format!("trash: {} ({})", item.title, item.id.as_str())
  • Impact confirmed: Newlines/control chars in titles corrupt git log output.

Finding 3 — WASM generate_device_keypair crosses private key to JS

  • File: crates/relicario-wasm/src/lib.rs
  • Claimed lines: 215-227
  • Verified: Function returns { "private_key_base64": "..." } as JsValue, exposing ed25519 private key to JavaScript heap.
  • Impact confirmed: Key material accessible to any JS in service worker context.

Finding 4 — Test env vars ship in production binary

  • File: crates/relicario-cli/src/main.rs
  • Claimed lines: 445-446, 421-423, 1425-1426
  • Verified:
    • Lines 421-423: RELICARIO_TEST_ITEM_SECRET
    • Lines 445-446: RELICARIO_TEST_PASSPHRASE
    • Lines 1425-1426: RELICARIO_TEST_BACKUP_PASSPHRASE
  • Impact confirmed: All checked in production code without #[cfg(test)]. Passphrase visible in /proc/<pid>/environ.

Finding 5 — AttachmentId truncated to 64 bits

  • File: crates/relicario-core/src/ids.rs
  • Claimed lines: 52-57
  • Actual lines: 51-56 (off by 1)
  • Verified: &digest[..8] = 8 bytes = 64 bits. Birthday collision at ~2³² work.
  • Impact confirmed: Attacker with attachment upload can cause silent overwrites.

Finding 6 — get_field_history returns plaintext to JS

  • File: crates/relicario-wasm/src/lib.rs
  • Claimed lines: 232-265
  • Verified: Returns historical Password/Concealed values as plaintext JSON via v.as_str().to_owned().
  • Impact confirmed: Password history exposed to JS heap without Zeroizing.

Finding 7 — Device key system is security theater

  • File: crates/relicario-cli/src/main.rs
  • Claimed lines: 2151-2221
  • Verified: cmd_device() handles Add/List/Revoke but:
    • No sign_commit or verify_signature functions exist anywhere
    • devices.json is plaintext and unauthenticated
    • Revocation has no enforcement mechanism
  • Impact confirmed: Users falsely believe device revocation provides security.

Finding 8 — Path traversal on backup restore

  • File: crates/relicario-cli/src/main.rs
  • Claimed lines: 1619-1626
  • Verified:
    for item in &unpacked.items {
        fs::write(target.join("items").join(format!("{}.enc", item.id)), ...)?;
    }
    
    item.id and attachment_id used directly in path construction with no validation.
  • Impact confirmed: Crafted .relbak with id = "../../.bashrc" escapes target directory.

Blockers Assessment

The audit's "Path to Certifiable Safety" section is accurate:

Blocker Verified Severity
B1 - Device key theater Real High
B2 - Backup KDF NFC Real Medium
B3 - Test env vars Real Medium
B4 - Path traversal Real Medium

All four blockers are confirmed. B1 is the most dangerous as it misleads users about their security posture.