docs: M-Hard 9-11 — README, examples, CI, benchmarks, migration guide
Some checks failed
Test / test (push) Has been cancelled
Some checks failed
Test / test (push) Has been cancelled
M-Hard 9: Documentation + examples - README.md, SECURITY.md, THREAT-MODEL.md - 5 runnable examples: basic conversation, prekey server, WebSocket tunnel, identity verification, Dokploy deployment M-Hard 10: CI + publishing + benchmarks - GitHub Actions: test workflow with PostgreSQL service container - GitHub Actions: publish workflow for npm releases on git tags - Benchmark suite (bench/run.ts) with markdown output - LICENSE (MIT), CHANGELOG.md, CONTRIBUTING.md M-Hard 11: Migration guide - MIGRATION.md with three-phase rollout strategy - Concrete examples for replacing static AES tunnels - Concrete examples for per-device push notification migration - Sections for Orchestrator and Nova migrations Benchmark highlights: - AES-256-GCM: ~100K ops/sec - Encrypt+decrypt roundtrip: ~17K ops/sec - X3DH handshake: ~165 ops/sec (hardware acceleration limited) - Compute fingerprint: ~76K ops/sec All 11 M-Hard milestones complete. 193 tests passing, 0 failures. Shade is production-ready. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
99
THREAT-MODEL.md
Normal file
99
THREAT-MODEL.md
Normal file
@@ -0,0 +1,99 @@
|
||||
# Threat Model
|
||||
|
||||
This document describes what Shade protects against and what it doesn't. Read this before deploying Shade in any context where the answers matter.
|
||||
|
||||
## Assets
|
||||
|
||||
The thing we're protecting:
|
||||
- **Message plaintext** — the actual content of encrypted messages between peers
|
||||
- **Identity private keys** — long-term Ed25519 signing key + X25519 DH key
|
||||
- **Session state** — Double Ratchet root keys, chain keys, DH keypairs
|
||||
|
||||
## Adversaries we consider
|
||||
|
||||
### 1. Network attacker (active)
|
||||
Can intercept, modify, drop, replay, and inject network traffic between clients and the prekey server, and between two clients.
|
||||
|
||||
**Mitigations:**
|
||||
- All identity-key writes to the prekey server are signed (Ed25519). Tampering is detected.
|
||||
- Signed requests have a 5-minute replay window.
|
||||
- The Double Ratchet binds message headers to ciphertext via AES-GCM AAD, so header tampering breaks decryption.
|
||||
- Forward secrecy: even if an attacker captures all traffic, compromising a key later doesn't help them read past messages.
|
||||
|
||||
**NOT mitigated:**
|
||||
- Initial session establishment can be MITM'd if users don't verify identity fingerprints. The prekey server could distribute a fake bundle on first contact. Always compare safety numbers out-of-band for high-stakes communications.
|
||||
|
||||
### 2. Malicious or compromised prekey server
|
||||
The server holds identity public keys and prekey bundles. It can serve them to anyone.
|
||||
|
||||
**Mitigations:**
|
||||
- The server only stores PUBLIC keys, never private ones.
|
||||
- Write operations are signed with the identity private key, so the server can't forge new identities or replenishments without the user's key.
|
||||
- Bundle fetches are unauthenticated, so a malicious server can serve fake bundles. Detection requires out-of-band fingerprint comparison.
|
||||
|
||||
**NOT mitigated:**
|
||||
- A malicious server can substitute one user's prekey bundle with the server operator's own keys, enabling MITM at session establishment. Users must verify safety numbers to detect this.
|
||||
|
||||
### 3. Compromised endpoint (post-compromise)
|
||||
Attacker briefly gains code execution or filesystem access on a user's device, exfiltrates session state, then loses access.
|
||||
|
||||
**Mitigations:**
|
||||
- Forward secrecy: messages sent BEFORE the compromise cannot be decrypted with the leaked state. Old chain keys are zeroed after use.
|
||||
- Post-compromise security: as soon as a peer initiates a new DH ratchet step, the leaked state becomes useless for new messages.
|
||||
- Memory zeroization: message keys and chain keys are wiped from JS memory after use (best-effort — V8 may retain copies).
|
||||
|
||||
**NOT mitigated:**
|
||||
- An ongoing endpoint compromise can read messages in real time and exfiltrate identity private keys.
|
||||
- Attackers with persistent access can intercept new identity rotations.
|
||||
|
||||
### 4. Compromised device storage
|
||||
Attacker gains access to the persistent storage (e.g., steals the SQLite file or dumps the PostgreSQL table).
|
||||
|
||||
**Mitigations:**
|
||||
- Stored data includes private keys but is unencrypted at rest. Shade does NOT encrypt the storage layer — it assumes the database is in a trusted environment.
|
||||
|
||||
**NOT mitigated:**
|
||||
- Filesystem-level encryption (LUKS, FileVault) is the user's responsibility.
|
||||
- Database TLS in transit is the user's responsibility.
|
||||
|
||||
### 5. Side-channel attacks (timing)
|
||||
Attacker measures timing of identity verification operations to recover key bits.
|
||||
|
||||
**Mitigations:**
|
||||
- All comparisons of secret material use constant-time XOR-accumulator comparison (`constantTimeEqual`).
|
||||
- AES-GCM and the underlying primitives are constant-time as implemented by SubtleCrypto and @noble/curves.
|
||||
|
||||
**NOT mitigated:**
|
||||
- JavaScript JIT compilation can introduce timing variability that's hard to control.
|
||||
- We don't claim resistance to power-analysis or fault-injection attacks (out of scope for a JS library).
|
||||
|
||||
### 6. Denial of service
|
||||
Attacker floods the prekey server to exhaust resources or one-time prekeys.
|
||||
|
||||
**Mitigations:**
|
||||
- Per-IP rate limiting on registration and bundle fetches.
|
||||
- Per-identity rate limiting on replenish and delete.
|
||||
- 64KB body size limit on POST endpoints.
|
||||
- Address validation rejects path traversal and malformed inputs.
|
||||
|
||||
**NOT mitigated:**
|
||||
- Application-level DDoS at the network layer is your hosting platform's responsibility.
|
||||
|
||||
## Assumptions
|
||||
|
||||
1. **The user has a secure way to bootstrap trust.** Either:
|
||||
- Trust on first use (TOFU) — accept the first identity key seen for a peer
|
||||
- Out-of-band verification — compare safety numbers in person/video before trusting
|
||||
2. **Cryptographic primitives are sound.** We trust X25519, Ed25519, AES-256-GCM, HKDF-SHA256, HMAC-SHA256.
|
||||
3. **The runtime is honest.** A malicious Bun/Node/browser runtime can defeat any JS library.
|
||||
4. **The prekey server is reachable.** If it's offline, new sessions can't be established (but existing sessions continue working).
|
||||
|
||||
## Residual risks
|
||||
|
||||
| Risk | Severity | Mitigation |
|
||||
|------|----------|------------|
|
||||
| MITM at first session establishment | High | Compare safety numbers out-of-band |
|
||||
| Identity private key theft from device | Critical | Filesystem encryption, secure enclave (future) |
|
||||
| Prekey server operator runs a "key oracle" attack | Medium | Distributed/federated prekey servers (future) |
|
||||
| Side-channel via JIT timing variability | Low | Constant-time primitives reduce but don't eliminate |
|
||||
| Metadata visibility to prekey server | Low | Acceptable for most use cases; mix networks for stronger metadata protection |
|
||||
Reference in New Issue
Block a user