Skip to content

Security model

Chris edited this page Nov 15, 2026 · 1 revision

Security model

To report a vulnerability, see SECURITY.md.

  • Read-only host access. The bot reads /proc, /sys, the Unraid emhttp directory, config.toml, and the helper socket directory through read-only mounts. It writes only to its own /data volume and to an in-memory /tmp.

  • Locked-down containers. Compose starts two containers, shazzzbot and docker-proxy. Each has a read-only root filesystem, no Linux capabilities, and no-new-privileges. The bot runs as user id 10001, and the proxy runs as root. The bot has a limit of 512 MB of memory and 128 processes. The proxy has a limit of 128 MB and 64 processes. Docker keeps at most three 10 MB log files for each container.

  • Docker proxy allowlist. The bot never touches the Docker socket. It talks to docker-proxy, an HAProxy container that permits three requests only:

    • GET /containers/json (list containers).
    • GET /info (engine information).
    • POST /containers/<id>/restart (restart one container). The id or name must start with a letter or a digit.

    Each path can start with an API version, for example /v1.47. The proxy refuses every other request with 403. The proxy has no published port, so only containers on the Compose network can reach it.

  • Deny by default. A command runs only for a role or user listed in a tier that allows it. It also runs only in the configured server, and only in an output channel or in commands_channel_id. Only /about is open to all users.

  • Confirm and audit. A restart needs a click on Confirm. The bot posts each change to the audit channel with a mention of the person who made it. The mention does not ping.

  • Fail closed. If the audit channel is not set or the bot cannot see it, /charts window, /blowup, /update, and all /docker commands refuse to run. A restart also stops when its audit post fails.

  • [restarts] allow. The /docker commands accept only containers that match a pattern in [restarts] allow, also for a group from [restarts.groups]. The default empty list turns restarts off (see Restarts).

  • Host helper. The optional Host helper runs as root and serves fixed reads over a Unix socket. It keeps its files in one private directory on a pool. Each request needs a signature made with a shared key. The bot sends only the hello, tasks, and ups_shutdown actions.

  • Pinned relay. The bot checks the certificate of each relay against RELAY_FINGERPRINT before it sends the key. The relay accepts only TLS 1.3 (see Relay).

  • Secrets in the environment. The Discord token, the Jellyfin key, the helper key, the relay keys, and the forge tokens come from environment variables. They are not in config.toml (see Environment variables).

  • Pinned dependencies. Dockerfile and compose.yaml pin the Python and HAProxy images by digest. requirements.txt locks each Python package, and the image build checks the hash of each package. setup.sh checks each helper file against the SHA-256 in the release.

Warning

The docker-proxy container mounts the Docker socket, and access to that socket is equal to root access on the server. Do not publish its port 2375 and do not add rules to docker-proxy/haproxy.cfg unless you understand each new request.

Clone this wiki locally