onionwire/docs/SECURITY_AUDIT.md
Sirius DevOps 22b3a0062a
Some checks are pending
ci / test (pull_request) Waiting to run
docs: add PROTOCOL.md and retire the stale audit writeup
Wire format lives in docs/PROTOCOL.md so the handshake, invite, and
frames can be read without the Rust. Threat model points at it. The
in-house audit notes are a finding-status table, not a third-party
audit. SDK README no longer claims the legacy concat invite signature
is what we encode.
2026-09-11 13:15:51 -04:00

39 lines
2.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# OnionWire security notes
**This is not a public third-party audit.** It is an in-house review of
commit `2b42864` plus a status check against the current tree. Do not cite it
as “audited.”
Protocol: [PROTOCOL.md](PROTOCOL.md). Claims: [THREAT_MODEL.md](THREAT_MODEL.md).
Original pass: rust-dev, no live hidden service / live wallet. Ignored tests
(`rotate_hs`, `tor_hs`, `two_node`) were not run.
## Finding status (vs current tree)
| Id | Original | Now |
|---|---|---|
| F1 receipt `verified` on OR-match | High — txid **or** addr+amount | **Fixed.** `transfers_match` requires txid ∧ amount ∧ address, all non-empty. |
| F2 chat AEAD empty AAD | Medium — row swap | **Fixed.** AAD `owmsg1 \|\| friend_id_le64 \|\| dir \|\| 0x00 \|\| row_id_le64`. |
| F3 invite concat signature | Medium — field shift | **Fixed on encode.** Domain tag `onionwire-invite-v1` + `0x00` separators. Decode still **accepts** legacy concat so old invites work. |
| F4 Monero address shape-only | Medium | **Fixed.** Base58 + Keccak checksum + network prefixes. |
| F5 wallet RPC no auth | Medium | **Fixed.** HTTP Digest required; open RPC refused; 1 MiB read cap; `.onion` RPC URLs refused. |
| F6 `/wipe` skipped payments | Low | **Fixed.** `/wipe` also `DELETE FROM payments` + WAL checkpoint. Still not forensic. |
| F7 HS logs unredacted onion | Low | **Fixed.** stderr uses a redacted label. `dangerously_trust_everyone` remains on Arti storage only. |
| F8 threat model vs F1F3 | Low | **Fixed** in [THREAT_MODEL.md](THREAT_MODEL.md) when the code landed. |
## Still true / not a “finding we forgot”
- Identity secret key and roster (pubkeys + locators) are **plaintext** in sqlite. Chat bodies are not. Seized laptop without FDE yields who you are and who you talk to.
- Arti onion services are experimental. Fail closed; no C-tor fallback.
- No public third-party audit, no `cargo-audit` gate in CI as of the original pass.
- Invite decode still accepts the legacy concat signature (compatibility).
- Rate limit is availability, not traffic-analysis defense.
- One-shot sessions: no channel binding across file chunks beyond “same Noise peer.”
## Verified correct (original pass, still the protocol)
Noise is `Noise_IK_25519_ChaChaPoly_BLAKE2s`, prologue `onionwire-v1`, 96-byte
identity proofs, loc/prf/inv/rcp signed under the session identity, unknown
`[a-z]{3} ` prefixes dropped, frames length-checked before allocate. See
[PROTOCOL.md](PROTOCOL.md).