solvox / SECURITY.md
muthuk1's picture
🎀 SolVox: Voice-First Private AI Wallet for Solana β€” Powered by QVAC SDK
945e815 verified

πŸ›‘οΈ 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