# 🛡️ SolVox Security Model ## Threat Model SolVox operates under the assumption that: 1. The **renderer process is untrusted** — it could be compromised via XSS 2. The **main process is the trust boundary** — all key operations happen here 3. The **local filesystem is semi-trusted** — OS-level encryption protects at-rest data 4. The **network is adversarial** — only Solana RPC calls leave the device ## Security Controls ### 1. Process Isolation | Control | Setting | Purpose | |---|---|---| | `contextIsolation` | `true` | Renderer cannot access Node.js globals | | `nodeIntegration` | `false` | No `require()` in renderer | | `sandbox` | `true` | OS-level process sandbox (Chromium) | | `webSecurity` | `true` | Same-origin policy enforced | | `allowRunningInsecureContent` | `false` | No HTTP content in HTTPS context | | `navigateOnDragDrop` | `false` | Prevents file drag-and-drop navigation | ### 2. IPC Channel Allowlist The preload script exposes ONLY these namespaced channels via `contextBridge`: ``` wallet:create, wallet:import, wallet:getPublicKey, wallet:getBalance, wallet:sendSOL, wallet:sendUSDT, wallet:getHistory, wallet:isUnlocked, wallet:lock, wallet:exists auth:biometric, auth:unlock, auth:setPin, auth:biometricAvailable security:getSettings, security:updateSettings, security:addWhitelist, security:removeWhitelist, security:getWhitelist, security:getAnomalies ai:initialize, ai:processVoice, ai:chat, ai:parseIntent, ai:speak, ai:translate, ai:embed, ai:ocr, ai:getStatus rag:search, rag:addDocument ``` **No raw `ipcRenderer` is ever exposed.** The renderer cannot invoke arbitrary IPC channels. ### 3. Key Storage ``` Mnemonic/Private Key │ ▼ PIN-based AES-256-GCM (PBKDF2, 600K iterations, SHA-512) │ ▼ Electron safeStorage (OS keychain: macOS Keychain / Windows DPAPI / Linux libsecret) │ ▼ File on disk (0600 permissions, owner-only) ``` The mnemonic is **double-encrypted**: first with the user's PIN (AES-256-GCM with PBKDF2-derived key), then with OS-level `safeStorage`. An attacker who obtains the vault file still needs: 1. The user's OS login credentials (to decrypt safeStorage) 2. The user's PIN (to decrypt the inner AES layer) ### 4. In-Memory Key Handling - The `Keypair` object lives exclusively in the main process's `_sessionKeypair` variable - On lock: `secretKey.fill(0)` zeroes the key buffer (best-effort; V8 GC is non-deterministic) - Auto-lock triggers after 5 minutes of inactivity - Key material is NEVER sent over IPC — only the public key (base58 string) and signed transaction bytes ### 5. Transaction Guards | Guard | Protection | |---|---| | **Input validation** | Regex-validated addresses, bounds-checked amounts | | **Per-tx limits** | Configurable maximum per transaction | | **Daily volume** | Cumulative daily spend limit | | **Velocity** | Max transactions per hour | | **Cooldown** | Minimum time between transactions | | **Whitelist** | Optional — only send to pre-approved addresses | | **Anomaly detection** | AI-powered pattern analysis (high amounts, odd hours, rapid sequences) | | **Confirmation** | Every transaction requires explicit user confirmation | ### 6. Content Security Policy ``` default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; connect-src 'self' https://api.mainnet-beta.solana.com https://api.devnet.solana.com; object-src 'none'; base-uri 'self'; form-action 'self'; frame-ancestors 'none'; ``` - No `unsafe-eval` — prevents `eval()` and `new Function()` attacks - No external scripts — blocks CDN-based script injection - Limited connect-src — only Solana RPC endpoints allowed - No frames — prevents clickjacking ### 7. Navigation Protection - All navigation to non-local URLs is blocked - New window creation is denied (`setWindowOpenHandler(() => ({ action: 'deny' }))`) - DevTools are disabled in production builds ## Data Flow ``` Voice Input ──→ QVAC (local) ──→ Intent ──→ Main Process validates ──→ Wallet signs ──→ Solana RPC │ ▼ TransactionGuard checks: ├── Address format valid? ├── Amount within limits? ├── Daily volume OK? ├── Velocity limit OK? ├── Address whitelisted? ├── Anomaly detected? └── User confirmed? ``` **Only the signed transaction bytes leave the device** — via Solana RPC. All AI processing, intent parsing, and validation happen locally. ## Known Limitations 1. **V8 garbage collection** means `secretKey.fill(0)` doesn't guarantee the key is erased from all memory pages 2. **Electron renderer** could theoretically be compromised via a 0-day in Chromium — contextIsolation + sandbox mitigate this 3. **Transaction privacy** is limited by Solana's public blockchain — recipients and amounts are on-chain 4. **PIN brute-force** is mitigated by PBKDF2 (600K iterations) + lockout, but a sufficiently weak PIN (e.g., `123456`) can still be guessed ## Recommendations for Production - Use a hardware security module (HSM) or secure enclave for key storage - Implement Shamir's Secret Sharing for mnemonic backup - Add a dead man's switch (auto-transfer if inactive for N days) - Integrate with hardware wallets (Ledger/Trezor) for signing - Add transaction simulation (Solana `simulateTransaction`) before signing