Self-host and operate

Security

Automata reduces the authority given to an AI client, but operators still control the upstream credentials and infrastructure that define the ultimate boundary.

Credential boundaries

Keep browser sessions and MCP authentication separate. The web UI uses an HTTP-only session cookie stored only as a SHA-256 hash; MCP requests use connector tokens only.

Web sign-in is hardened in three ways:

  • Sign-up is invite-only by default. Every self-signup creates a new organization administrator, so leave NUXT_SIGNUP unset or set a NUXT_SIGNUP_CODE. See Who can sign up.
  • Email addresses are verified once SMTP is configured, so nobody can register an address they do not own ahead of its owner. See Email verification.
  • Failed sign-ins are throttled per email and per client address, and users can add two-factor authentication with an authenticator app, passkey, or security key.

Evolution global keys provision instances, while normal WhatsApp calls use per-instance tokens. The Telegram administrator key provisions sessions, while normal calls use per-session credentials. Do not add a fallback from a missing per-connection key to a global key.

Connector tokens

Raw connector tokens are shown once and stored only as SHA-256 hashes. Automata redacts /mcp/<token> paths and authorization headers from its own error paths, but operators should still prefer bearer headers and ensure proxy logs do not capture secrets.

Issue separate tokens per client, choose expiries, scope narrowly, and revoke any token exposed in chat, support tickets, logs, or source control.

Database roles

Use least-privilege roles for user database connections. Evolution message reads run only fixed, parameterized SELECTs in read-only sessions, so the owner URL works there; a SELECT-only role is optional hardening. Tool plan checks cannot see everything triggers or user-defined functions may do, and a superuser can bypass normal database restrictions.

Grant only required schemas, tables, and statement types. Keep run-statement off unless the workflow truly requires writes.

Network protections

The outbound host guard blocks private and loopback targets by default and always blocks Automata internal services. Leave NUXT_ALLOW_PRIVATE_TARGETS off for shared environments, and never pair it with open sign-up. In the single container, every backend is on loopback and Redis is not on the refused list, so turning it on there reaches more.

Set NUXT_WEBHOOK_SECRET. Evolution does not sign webhook payloads itself; Automata registers per-instance webhooks carrying this shared header, then treats each delivery as a prompt to re-read live state rather than trusting payload state.

Serve the web app only over HTTPS. The Docker Compose stack publishes plain HTTP on WEB_PORT, so place a TLS-terminating reverse proxy in front of it before exposing it to the internet.

Do not expose Evolution, Redis, Postgres, or bridge administration publicly unless protected by an additional trusted network boundary.

Storage and backups

Connection credentials in the app schema (Evolution keys, bridge keys, and user connection strings) never leave the server, but they are not encrypted at rest. Treat NUXT_DATABASE_URL and every Postgres backup as holding every connected account, and restrict backup access accordingly.

Telegram sessions are encrypted with TELEGRAM_SESSION_ENCRYPTION_KEY. Store the key separately from database backups and preserve it through deploys. Restrict access to the Evolution instance volume because it holds active WhatsApp pairings.

View source