v0.1.1
First security-hardened release. The internal audit
(docs/AUDIT_2026-05-16.md, 8 CRITICAL + 6 WARNING) is fully remediated and all
non-deferred follow-ups are closed. Verified gate: 95/95 tests, clippy --all-targets clean, fmt/build --release/doc clean, audit baseline.
Security
- Filesystem sandbox closed on all tools.
write.rsandgrep.rsnow route throughPathGuard::validate; thebashtool sandboxes every non-flag argument, closing the Windows forward-slash absolute-path escape (C:/...). - Crypto hardening. Independent
OsRngnonce per record; Argon2id pinned to OWASP 2025 parameters (64 MiB, t=3, p=4); a hard cap on the decrypt length-prefix to prevent hostile allocations. - Ephemeral fallback (no constant key). An inaccessible OS keyring degrades the session to in-memory only — it never falls back to a constant passphrase.
- OAuth callback timeout. The PKCE callback server is bounded by a timeout; state is enforced (CSRF protection).
- Secrets separation preserved. API key (
magi-rs) and DB master key (magi-rs-internal) remain in separate keyring services; rotating one never invalidates the other.
Changed
- One key derivation per session (B′). Argon2 no longer runs per record. A per-DB salt is persisted in a new
vault_metatable and the 32-byte key is derived once at construction and cached (Zeroizing), removing the O(N) cost on history load. Blob layout is now[u8 version][u32 LE len][RS(nonce‖ciphertext)]. - SSE wire path is byte-buffered. The streaming reader buffers
Vec<u8>and decodes only complete\n\nblocks, so a multi-byte UTF-8 character split across a network chunk is never decoded mid-character. tool_useis assembled from the stream.AnthropicProvidernow buildsContent::ToolUsefromcontent_block_start/input_json_delta/stop(previously tools were inert with the real provider).- In-session
/login. A successful login rebuilds the running agent's provider without a restart; the cannedStaticProviderhistory is cleared only when the prior provider was static, and the banner refreshes. - Dependency:
magi-corebumped0.6→1.0.1.
Added
- Salt integrity & self-heal. The per-DB salt is RS-encoded with a SHA-256 checksum; an absent/corrupt/unrecoverable salt self-heals to a fresh start instead of bricking, and minor bit-rot is corrected.
- Poisoned-lock recovery. A poisoned connection mutex recovers (
into_inner+ warn-once) so persistence continues for the rest of the session. - Idempotent salt bootstrap. Salt read + reset run inside a
BEGIN IMMEDIATEtransaction with an in-tx re-check, closing the concurrent first-open TOCTOU. - Blob version byte (
BLOB_VERSION), validated before any allocation. - TUI startup notices. Keyring-unavailable (no persistence) and history-reset (fresh start) states surface as startup
Infomessages instead of pre-TUI stderr; the store exposeswas_reset().
Fixed
- Malformed tool-input JSON logs a warning (tool name/id + error) instead of silently degrading to
{}. - Default-model fallback handles a blank/whitespace/absent
key.txtmodel line. - Full
clippy --all-targetsand tree-widerustfmtbaseline established.
Notes
- No on-disk migration (D2/D6 fresh-start). The blob layout and KDF changed without a migration path: a pre-0.1.1
.magi-rs-memory.dbdeterministically resets to a fresh, empty store on first open. This is intentional for the pre-1.0 single-user threat model.
Full Changelog: https://github.com/BolivarTech/magi/commits/v0.1.1