Sandboxing & Security
Suitcase is a local-first agent. It runs in Docker, connects to your LLM, and stores everything locally.
Security Audit
Before remote exposure or after changing channel config, run the security audit:
./scripts/security_audit.sh # baseline audit
./scripts/security_audit.sh --deep # deep scan (secrets, images, webhooks)
./scripts/security_audit.sh --fix # auto-fix permissions
./scripts/security_audit.sh --deep --fix # full audit + auto-fix
./scripts/security_audit.sh --json # JSON output for machinesThe audit checks:
| Category | Checks |
|---|---|
| Network | Port binding (loopback vs 0.0.0.0) |
| Docker | Socket mount, runtime sandbox, running containers |
| Channels | Discord/Telegram DM policies, allowlists, pairing |
| Secrets | LLM API key presence, .env permissions, GitHub token type |
| Tools | Write confinement, risky power combinations |
| Install | Root user, Docker Compose version, volume permissions |
Deep mode (--deep) adds:
- Secret scanning of suitcase_world/ files for leaked tokens
- Docker image inspection
- Env file permissions (comprehensive)
- Channel webhook verification
- Running container and volume inspection
Fix mode (--fix) auto-remediates:
.envpermissions → 600suitcase_world/permissions → 700suitcase_world/secrets/permissions → 700,*.json→ 600- Disables risky channel powers (Discord, Telegram)
Also available as an API: GET /api/security/audit?deep=true&fix=true
Local-First Boundary
- The FastAPI app serves the web UI on
localhost:8000. - The SQLite database is stored in the
suitcase-dataDocker volume. - Agent memory and generated artifacts live in
suitcase-worldandsuitcase-logsvolumes. - LLM credentials are stored server-side and never returned to the browser after save.
Write Confinement
All writes must resolve inside suitcase_world/. The path guard blocks:
- Absolute paths outside the world root
- Parent directory traversal with
.. - Symlink escapes
This keeps reflections, reports, and career artifacts in isolated, reviewable storage.
Secrets
Secrets stay server-side:
- LLM API keys are saved via the Setup UI and stored in Docker secrets.
- The setup API reports whether a key exists, not the key value.
- Powers requiring tokens (Discord, Telegram, Brave, GitHub, Restic) accept values through inline password fields — values are never returned to the browser.
- Logs and diagnostics avoid printing secret values.
If you accidentally paste a token into a world file or chat message, rotate that token.
Command Logger
When the Command Logger power is enabled, every tool call is logged to suitcase_world/logs/commands.log (JSONL). Secret-bearing input fields are redacted.
Model Choice Matters
The LLM is part of the security boundary because it must follow Suitcase's system prompt, world rules, and tool instructions.
- Cloud models (OpenAI, Anthropic) are the recommended default for safety and instruction-following reliability.
- Local models can be used via the compatible modes. Models below 8B parameters may struggle with prompt injection resistance. Gemma 4 26B MoE is a verified local baseline.
Integrations
- Discord: Bot token stored server-side. Messages are treated as untrusted input.
- Telegram: Bot token stored server-side. Allowed user IDs restrict access.
- GitHub: Token stored in
.envor via Setup UI. Used for repo evidence sync. - Brave Search: API key stored via Setup UI. Rate-limited to 1 request/second via SKILL.md guidance.
- Phone Location: Webhook secret stored via Setup UI. Accepts location data from OwnTracks/GPSLogger.
What To Review
Review these before trusting a new setup:
suitcase_world/WORLD.mdfor world rules and safety boundariessuitcase_world/SOUL.mdfor voice and trust principles.envfor local configuration and secrets- The setup dashboard to verify which powers are enabled
For the broader architecture, see Architecture.