# Security Policy ## Reporting a Vulnerability **Critical or high severity** (key leakage, authentication bypass, ratchet desync that leaks plaintext, FFI memory corruption): > **security@lo.sh** Use this for anything an attacker could exploit. If you have our public key, encrypt the report. We will acknowledge within 72 hours and aim to ship a fix within 14 days of confirmation. **Medium or low severity** (interoperability bugs, non-exploitable logic errors, documentation issues): > Open an issue at **https://git.lo.sh/lo/libsoliton** When in doubt, use the email. We would rather triage a false alarm than miss a real vulnerability. ## Supported Versions | Version | Supported | |---------|-----------| | 0.1.x | Yes | Only the latest release is supported. Security fixes are not backported. ## Threat Model ### In scope - **Protocol logic** in LO-KEX, LO-Ratchet, KEM authentication, and storage encryption. Bugs here (wrong KDF inputs, missing domain separation, ratchet state corruption) are the primary risk. - **Memory safety** in the Rust code and the `unsafe` FFI boundary (`libsoliton_capi`). Unsound pointer handling, use-after-free in opaque state objects, buffer overflows in slice construction. - **Wrapper binding correctness** (`soliton_py`, `soliton_wasm`, `soliton_zig`). Incorrect type marshaling, use-after-free of opaque handles, missing zeroization at the binding layer, header serialization mismatches. The Python and WASM bindings wrap the core Rust API via PyO3 and wasm-bindgen respectively (no `unsafe` in the bindings themselves). The Zig wrapper consumes the C ABI directly. - **Key management** — failure to zeroize secrets, key material leaking into logs or error messages, nonce reuse. - **Cryptographic misuse** — wrong algorithm parameters, truncated hashes, clamping errors, incorrect domain separators. ### Out of scope - **Side-channel attacks in upstream Rust crates.** Timing, power, or EM side channels in ML-KEM-768 (`ml-kem`), ML-DSA-65 (`ml-dsa`), X25519 (`x25519-dalek`), or Ed25519 (`ed25519-dalek`) are upstream concerns. Report those to the relevant [RustCrypto](https://github.com/RustCrypto) or [dalek-cryptography](https://github.com/dalek-cryptography) project. XChaCha20-Poly1305 and Ed25519 are constant-time by construction (ARX operations only, no table lookups). - **WASM linear memory.** Secret key material in WASM cannot be reliably zeroized — the linear memory is GC-managed by the JS engine and may be copied, paged, or retained after `free()`. This is inherent to the WASM execution model, not a library bug. - **Python GC.** `bytes` objects returned by the Python binding are GC-managed. The Rust side zeroizes its copy, but the Python object persists until collected. Context managers (`with`) minimize the window. - **Compression oracle (CRIME/BREACH-style).** When streaming AEAD compression is enabled and an attacker controls partial plaintext, ciphertext length may leak information about co-resident secret content. File transfer (the primary use case) does not have attacker-controlled plaintext injection, so this is not exploitable in the intended deployment. Applications mixing attacker-controlled and secret data in a single compressed stream should disable compression. - **Hardware faults** — rowhammer, fault injection, glitching. - **Denial of service** — resource exhaustion from large inputs is a bug, but not a security vulnerability in a library context. ### Known limitations - **PQ crates are pre-1.0.** ML-KEM and ML-DSA are NIST FIPS 203/204 final, but the RustCrypto implementations (`ml-kem`, `ml-dsa`) have not undergone the same decades of scrutiny as, say, OpenSSL's AES. This is inherent to post-quantum cryptography in 2026. - **X-Wing is a draft.** We implement draft-connolly-cfrg-xwing-kem-09. The combiner and encoding may change before the RFC is finalized. - **Ed25519 (RFC 8032)** is used for classical signing via `ed25519-dalek`. Strict verification mode rejects non-canonical signatures and small-order public keys, preventing malleability attacks. - **XChaCha20-Poly1305** is constant-time by construction (ARX operations only — no table lookups or secret-dependent branches). No hardware acceleration is required; it runs at full speed on all platforms including RISC-V. ## Dependencies All dependencies are pure Rust — no C libraries, no cmake, no system linker dependencies. | Dependency | Role | |------------|------| | [ml-kem](https://crates.io/crates/ml-kem) | ML-KEM-768 (inside X-Wing) | | [ml-dsa](https://crates.io/crates/ml-dsa) | ML-DSA-65 hybrid signatures | | [ed25519-dalek](https://crates.io/crates/ed25519-dalek) | Ed25519 signing/verification | | [x25519-dalek](https://crates.io/crates/x25519-dalek) | X25519 (inside X-Wing) | | [chacha20poly1305](https://crates.io/crates/chacha20poly1305) | XChaCha20-Poly1305 AEAD | | [sha3](https://crates.io/crates/sha3) | SHA3-256 (HMAC, HKDF, fingerprints, X-Wing combiner) | | [hmac](https://crates.io/crates/hmac) | HMAC-SHA3-256 | | [hkdf](https://crates.io/crates/hkdf) | HKDF-SHA3-256 key derivation | | [argon2](https://crates.io/crates/argon2) | Argon2id password hashing | | [ruzstd](https://crates.io/crates/ruzstd) | Zstd decompression (storage blobs, streaming AEAD chunks) | | [zeroize](https://crates.io/crates/zeroize) | Secret wiping | **Binding-specific dependencies** (not part of the core library): | Dependency | Role | |------------|------| | [pyo3](https://crates.io/crates/pyo3) | Python FFI bridge (`soliton_py`) | | [wasm-bindgen](https://crates.io/crates/wasm-bindgen) | WASM/JS interop (`soliton_wasm`) | Vulnerabilities in these dependencies may affect libsoliton. We track upstream advisories and update pins accordingly.