π‘οΈ SolVox Security Model
Threat Model
SolVox operates under the assumption that:
- The renderer process is untrusted β it could be compromised via XSS
- The main process is the trust boundary β all key operations happen here
- The local filesystem is semi-trusted β OS-level encryption protects at-rest data
- 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:
- The user's OS login credentials (to decrypt safeStorage)
- The user's PIN (to decrypt the inner AES layer)
4. In-Memory Key Handling
- The
Keypairobject lives exclusively in the main process's_sessionKeypairvariable - 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β preventseval()andnew 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
- V8 garbage collection means
secretKey.fill(0)doesn't guarantee the key is erased from all memory pages - Electron renderer could theoretically be compromised via a 0-day in Chromium β contextIsolation + sandbox mitigate this
- Transaction privacy is limited by Solana's public blockchain β recipients and amounts are on-chain
- 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