diff --git a/docs/SECURITY-ROADMAP.md b/docs/SECURITY-ROADMAP.md index 67e7d2a..ba38253 100644 --- a/docs/SECURITY-ROADMAP.md +++ b/docs/SECURITY-ROADMAP.md @@ -1,95 +1,111 @@ -# DigiByte.X Wallet — Security Roadmap - -Derived from `D:\Dev\SilentCode\web_wallet_security_analysis.md` (the -general web-wallet threat model) and mapped onto what this wallet -actually does today. Each item says where we stand and what the next -concrete step is. Ordered by the analysis' own priority: CSP first, -then key-splitting, then hardware isolation. - -Last reviewed: 2026-09-09. - ---- - -## Where we stand against the threat model - -| Threat (analysis §1–2) | Status | Notes | -|---|---|---| -| Custodial key control | ✅ N/A | Non-custodial. Seed never leaves the browser; only signed tx bytes go out. | -| Server breach exposes keys | ✅ Mitigated | Nothing key-related on the server. Encrypted blobs live only in the user's `localStorage`. | -| Phishing / typo-squat | ⚠️ Partial | `digibyte.x` is a BNS name with IP + TLS fingerprint on-chain, so wallet-aware clients pin the server. Plain browsers reaching us through `navigate.st` trust that gateway's TLS. | -| XSS / injected script | ✅ Mitigated | Strict CSP live on `digibyte.x/web/` since 2026-09-06 (`script-src 'self'` + hash of the one inline script); asset tags carry SRI since 2026-09-09. | -| Malicious extensions | ⚠️ Inherent | Nothing in-page can stop an extension with page access. Mitigation is the multi-sig item below. | -| Local malware reading storage | ⚠️ Partial | Blobs are PBKDF2-210k + AES-GCM under the master password. Persistent PIN blob (100k rounds) weakens this for users who set a PIN — documented in `session-auth.ts`. | -| DNS spoofing | ✅ Mitigated for pinned clients | On-chain fingerprint pinning; see `ops/nginx-digibyte-x.conf` header comment. | - -## What the wallet already does (analysis §2 "Client-Side Architecture") - -- **Local cryptography.** BIP39/BIP32 via `@dgb-wallet/core`; WebCrypto PBKDF2 + AES-GCM in `packages/keystore` and `packages/web-ui/src/session-auth.ts`. -- **Encrypted local storage.** One master password per device; every wallet blob encrypted under it. Session auto-locks after 30 min idle. PIN is a shortcut with a 3-attempt budget; the master password restores it. -- **Local signing.** PSBT built and signed in `SendScreen.tsx`; keys are derived on demand and dropped with the component. -- **Verified broadcast.** `packages/p2p/src/broadcast.ts` treats a send as done only when an uninvolved peer announces the tx back (DGB Core drops policy failures silently). Fees sized to DGB's 100 sat/vB relay floor. -- **Address hygiene (opt-in).** Settings → Security → "Fresh addresses" rotates receive and change addresses to the first unused index. Off by default because "used" is only complete with Blockbook enabled. - ---- - -## Roadmap - -### 1. Strict Content Security Policy — MANDATORY (analysis §3) — ✅ APPLIED 2026-09-06 - -Add to the nginx `location /web/` block on the VPS (and keep `ops/nginx-digibyte-x.conf` in sync): - -```nginx -add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'sha256-MYCXjyaeuO4n6g9JktOO1yXmG9rBTuGJ5Wk4GojDwig=' 'wasm-unsafe-eval'; style-src 'self' 'unsafe-inline'; connect-src 'self' https://api.coingecko.com; img-src 'self' data:; base-uri 'self'; frame-ancestors 'none'; form-action 'none'; object-src 'none'" always; -``` - -Notes: -- The `sha256-…` value is the hash of the inline ``-fixing script in the **built** `dist/index.html`. It changes whenever `packages/web-ui/index.html`'s inline script changes; recompute on each such change (a one-liner is in the deploy notes below) or move the script to a separate file under `assets/` to drop the hash entirely. -- `base-uri 'self'` (not `'none'`): the inline script injects a `` tag pointing at our own origin. -- `connect-src` needs CoinGecko only while the price feed is opt-in enabled; everything else (`../p2p/`, `../blockbook/`) is same-origin. -- `'unsafe-inline'` for styles is needed by a handful of inline `style=` attributes; removing them is a cleanup item, not a blocker. -- The `navigate.st` gateway serves the same HTML under its own headers; CSP there is the gateway's to set. - -Recompute the hash after a build: - -```bash -python -c "import re,hashlib,base64;h=open('packages/web-ui/dist/index.html',encoding='utf-8').read();s=re.findall(r'',h,re.S)[0];print('sha256-'+base64.b64encode(hashlib.sha256(s.encode()).digest()).decode())" -``` - -Applied and verified (zero violations through both digibyte.x and the navigate.st gateway). The repo mirror is `ops/nginx-digibyte-x.conf`; `ops/push.sh` warns when the live header's hash no longer matches the built inline script. - -### 2. Subresource integrity + reproducible bundle — ✅ SRI done 2026-09-09 - -- ✅ `integrity="sha384-…"` + `crossorigin` on the `',h,re.S)[0];print('sha256-'+base64.b64encode(hashlib.sha256(s.encode()).digest()).decode())" +``` + +Applied and verified (zero violations through both digibyte.x and the navigate.st gateway). The repo mirror is `ops/nginx-digibyte-x.conf`; `ops/push.sh` warns when the live header's hash no longer matches the built inline script. + +### 2. Subresource integrity + reproducible bundle — ✅ SRI done 2026-09-09 + +- ✅ `integrity="sha384-…"` + `crossorigin` on the `