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