3.0 KiB
id, name, status, depends_on, scope, risk, impact, level
| id | name | status | depends_on | scope | risk | impact | level | |
|---|---|---|---|---|---|---|---|---|
| vault/unlock-new-zeroizing-return | Change unlock_new return type from String to Zeroizing<String> | completed |
|
single | low | isolated | implementation |
Description
Fix drift item #8: unlock_new currently returns String, which is not
zeroized on drop. The mnemonic phrase is the root of trust — it must not linger
in freed heap memory. Change the return type to Zeroizing<String> (from the
zeroize crate, already a dependency).
Current state
pub fn unlock_new(&self, word_count: usize) -> Result<String, VaultServiceError>;
Target state
pub fn unlock_new(&self, word_count: usize) -> Result<Zeroizing<String>, VaultServiceError>;
Per docs/architecture/crates/vault/service.md → unlock_new:
The returned phrase is the root of trust — it is heap-allocated and zeroized on drop, so it does not linger in freed memory. The caller should extract the phrase for secure storage (write down, display to user) and let the
Zeroizing<String>drop when done. Do not clone the returned value or store it in a non-zeroizing container.
Caller adaptation
The assembly layer (CLI binary, not yet implemented) will call unlock_new and
extract the phrase. The Zeroizing<String> wrapper derefs to String, so
&*result or result.as_str() works for reading. The caller must not clone the
inner String into a non-zeroizing container.
Existing tests that call unlock_new need updating to handle the new return
type — use &*phrase or phrase.as_str() to read the string.
Scope
This task touches service.rs (the method signature and body) and test files.
It depends on the irpc removal task (drift #4) because both modify service.rs.
Acceptance Criteria
unlock_newreturn type changed fromResult<String, ...>toResult<Zeroizing<String>, ...>- Method body constructs
Zeroizing<String>from the generated phrase - Existing tests updated to handle
Zeroizing<String>return type - No
clone()of the returned value in non-test code cargo checksucceedscargo testsucceedscargo clippysucceeds with no warnings
References
- docs/architecture/crates/vault/README.md — Known Source Drift table item #8
- docs/architecture/crates/vault/service.md — unlock_new section
- docs/architecture/decisions/025-vault-local-only-dispatch.md — ADR-025 (resolves W7)
Notes
The mnemonic is the root of trust. Returning a plain
Stringmeans the phrase lingers in freed heap memory after the caller drops it.Zeroizing<String>zeroizes the bytes on drop. This resolves review #002 W7. Depends on irpc removal because both modifyservice.rs.
Summary
Changed unlock_new return type from Result<String, ...> to
Result<Zeroizing<String>, ...>. The generated mnemonic phrase is wrapped in
Zeroizing::new() so it is zeroized on drop. Existing tests work via Deref
coercion. All tests pass; clippy clean. Merged to develop.