English | [日本語](security-hardening.ja.md) # Security Hardening Guide MAESTRO runs LLM-driven tasks that execute code, fetch the web, drive a browser, and optionally run SSH commands. **Treat it as a privileged service.** This guide turns the baseline in [SECURITY.md](../SECURITY.md) into an actionable, ordered checklist for moving from "works on my laptop" to "safe for others to reach." For how to report a vulnerability, see [SECURITY.md](../SECURITY.md). For where secrets live and their file permissions, see its *Secrets and Data* section. ## Threat model in one paragraph Anyone who can reach the UI/API can create tasks, and a task can run tools (Bash, web, browser, files, and — if enabled — SSH/MCP). Without authentication that means anyone who can reach the port can run code on the host. The default deployment is therefore **localhost-only and unauthenticated**; everything below is about safely widening that. ## 1. Network exposure - The app binds to `127.0.0.1` by default (bare metal) and Docker Compose publishes only `127.0.0.1:9876`. Keep it that way until auth and TLS are in place. - When you do expose it, change the bind/port deliberately (`server.port`, the Compose port mapping) and front it with TLS — either MAESTRO's native HTTPS (`server.tls`) or a reverse proxy. ## 2. Authentication Authentication is **off by default**. Before exposing the service beyond localhost, turn it on: - **OAuth** (Google / Gitea) or **local accounts** (email + password). Configure under `auth` in `config.yaml` or via Settings → Authentication. - Set `auth.primary_provider` (`google` | `gitea` | `local`) when more than one provider is enabled to avoid an unintended login path. - Restrict who becomes admin via `auth.admin_emails`. - Set a stable `auth.session_secret` (or rely on the persisted `data/secrets/session-secret.key`); share it across nodes in a multi-node deployment so sessions survive failover. ## 3. Authorization and visibility Tasks, schedules, and jobs carry an owner and a visibility scope: `private` (owner + admin), `org` (members of the same organization), or `public` (any logged-in user). Default new resources to `private` and grant `org`/`public` only deliberately. Admins can see everything — keep the admin set small. ## 4. The Bash sandbox The `Bash` tool runs inside a sandbox controlled by `safety.bash_sandbox`: - `auto` (default) — use bubblewrap when available, otherwise a hardened allowlist. - `always` — **required for multi-user / untrusted deployments**; fails closed if bubblewrap is unavailable rather than silently downgrading. - `off` — no isolation; only for a trusted single operator. bubblewrap needs unprivileged user namespaces. See [operations/bash-sandbox-provisioning.md](operations/bash-sandbox-provisioning.md) and, for containers, [docker.md](docker.md). ## 5. Transport security (TLS) - Enable `server.tls` for native HTTPS, or terminate TLS at a reverse proxy. - Set `auth.secure_cookie: true` whenever TLS terminates upstream (behind a proxy) so the session cookie carries the `Secure` flag. Native TLS sets it automatically. - The default self-signed certificate makes browsers warn; install a real certificate for anything others use. ## 6. The metrics endpoint `/metrics` exposes operational data. In production, restrict it: - set a `bearer_token` (worker and/or gateway metrics config), and/or - limit `allowed_hosts` to the scraper's source IPs. Do not leave `/metrics` open on an internet-facing deployment. ## 7. Tools and integrations Each enabled capability widens the blast radius. Before granting access to untrusted users, review which tools and integrations are on: - **SSH** — runs commands on remote hosts; credentials are envelope-encrypted with the master key. Enable only for trusted operators. - **MCP** — external tool servers; credentials require `MCP_ENCRYPTION_KEY`. - **Browser** — drives a real Chromium; treat fetched/automated content as untrusted input. ## 8. Secrets See the *Secrets and Data* section of [SECURITY.md](../SECURITY.md). In short: generated secrets live under `data/secrets/` at mode `0600`, are gitignored and dockerignored, and core dumps are excluded because they can contain decrypted keys. Rotate after any suspected exposure and review the audit log. ## 9. Updates and monitoring - Track releases and apply security fixes promptly (fixes land on the latest release and `main`). - Review the audit log after permission or configuration changes. ## Production checklist Copy-paste before exposing MAESTRO to anyone but yourself: - [ ] Authentication enabled (`auth.*`), `primary_provider` set, `admin_emails` minimal - [ ] Stable `auth.session_secret` (shared across nodes if clustered) - [ ] `safety.bash_sandbox: always` - [ ] TLS terminated (native `server.tls` or a proxy) + `secure_cookie` matched - [ ] Bind/port restricted to the intended interface - [ ] `/metrics` protected (`bearer_token` and/or `allowed_hosts`) - [ ] New resources default to `private`; `org`/`public` granted deliberately - [ ] SSH/MCP/browser reviewed; enabled only as needed - [ ] Secrets out of version control and backups; rotation plan in place - [ ] A process to apply security updates