UnENVerse 2026-06-12
hex::encode(h.finalize()) == hash_hex — regular string comparison, vulnerable to timing attacks on legacy password hashes
Linking & Resolver Expansion (Prefix/Chunk/Cross-Chunk + Health/Server)
Full Bug Audit + Fixes
Security: Non-constant-time legacy SHA-256 comparison (vault-core/src/users.rs):
hex::encode(h.finalize()) == hash_hex— regular string comparison, vulnerable to timing attacks on legacy password hashes- Fix: decode
hash_hexto bytes; constant-time XOR-fold comparison:computed.iter().zip(expected.iter()).fold(0u8, |acc,(a,b)| acc | (a^b)) == 0 - No new crate dependency (avoids adding
subtle)
**Security: PUT /api/vault auth order** (envv-server/src/main.rs):
- Payload validation (api_keys check) ran before
extract_session()— unauthenticated malformed requests got 400 instead of 401 - Fix:
extract_session()moved before api_keys validation
**Security: GET /api/status unlocked logic** (envv-server/src/main.rs):
- Fix:
state.sessions.lock().unwrap().values().any(|s| s.is_owner)
**Functional: openAdd() listener leak** (src/ts/modals.ts):
- Added new
input/changelisteners on every call without removing previous ones - After N modal opens, each form field had N
saveDraftlisteners stacked — multiple sessionStorage writes per keystroke