46 lines
3.2 KiB
Markdown
46 lines
3.2 KiB
Markdown
|
|
# Security
|
|||
|
|
|
|||
|
|
One line: **the bot runs on your own machine; your data does not leave by default** — only the model API calls you choose, and (if you sign in to an account) the **ciphertext** of your backup.
|
|||
|
|
|
|||
|
|
**Reporting:** open a private security advisory on the repo (Gitea › Security) or write the owner. We aim to answer in 3 business days, fix in 90. No public disclosure of unfixed issues.
|
|||
|
|
|
|||
|
|
## Trust boundaries
|
|||
|
|
|
|||
|
|
- **Your computer** — the bot's brain, hands, `state.json`, vault. Your OS account is the boundary; shell commands run in the macOS sandbox (denies `~/.aws`, Keychain, AnyBot's own data).
|
|||
|
|
- **The bot's cloud box** — a Docker container the bot roots; automatically switched to gVisor (`runsc`) when the host has it: the kernel joins the boundary.
|
|||
|
|
- **Docker API** — no `docker.sock`: a docker-socket-proxy whitelist (containers/images/networks subset; no `exec`, no `privileged`).
|
|||
|
|
- **Relay** — stores hashes only: argon2id passwords, hashed tokens/sessions; your backup arrives sealed with a key derived from your password (PBKDF2-HMAC-SHA256 120k → AES-256-GCM). The relay never sees plaintext, and it is self-hosted.
|
|||
|
|
- **Model providers** — see the chats and screenshots you hand them, never your files, vault secrets, or keys.
|
|||
|
|
|
|||
|
|
## Where secrets live
|
|||
|
|
|
|||
|
|
| Thing | Where | What an attacker gets |
|
|||
|
|
|---|---|---|
|
|||
|
|
| Model API keys | `state.json` (0600) | that provider's bill — disk encryption, provider 2FA |
|
|||
|
|
| Vault (logins/cards) | `vault.bin`: AES-256-GCM, key in the system keychain (0600 file fallback) | nothing without the keychain; the model never sees secrets — lists come blanked, every fill is approved per use |
|
|||
|
|
| Account password | your app; relay keeps only argon2id (m=19MiB, t=2) | hashes; the backup stays sealed behind your password |
|
|||
|
|
| 2FA | TOTP secret + 8 hashed recovery codes on the relay | disabling 2FA needs password + code in the same turn |
|
|||
|
|
| Sessions | hashed rows; logout-everywhere | a stolen session file works until logout (relay is a trust point) |
|
|||
|
|
|
|||
|
|
## Prompt-injection defenses (layers, not walls)
|
|||
|
|
|
|||
|
|
1. Outside content is wrapped as `<untrusted>` — data, never orders.
|
|||
|
|
2. Sensitive clicks (send/pay/transfer/…): asked **every time**, direct mode included — no grant silences it; the gate is in the harness, not the prompt.
|
|||
|
|
3. First use of every app/computer needs your approval (policy at the data layer).
|
|||
|
|
4. Card numbers and OTPs in screenshots are painted black before the model sees them.
|
|||
|
|
5. Every turn's actions land in an auditable oplog → SQLite audit (30 days), with a phone timeline.
|
|||
|
|
|
|||
|
|
Honest limit: injection has no absolute defense — which is why the last line is a human at the approval gate. The model never issues its own passes.
|
|||
|
|
|
|||
|
|
## Network surface
|
|||
|
|
|
|||
|
|
Loopback by default; egress binds loopback plus detected Docker bridge gateways, never 0.0.0.0. The phone talks to your relay over Caddy HTTPS. LAN mode is opt-in and password-gated.
|
|||
|
|
|
|||
|
|
## Known limits
|
|||
|
|
|
|||
|
|
Same OS user = same trust; providers see chats/screenshots you send them; gVisor is optional on your box; backup security is bounded by your password; a breached relay leaks hashes and ciphertext, not plaintext.
|
|||
|
|
|
|||
|
|
## Hardening
|
|||
|
|
|
|||
|
|
Disk encryption, capped + 2FA'd provider keys, HTTPS-only relay with 2FA, gVisor on the box host, per-app "ask always" on your sensitive apps.
|