File size: 5,820 Bytes
945e815 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 | # π‘οΈ 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
|