Security
Last updated: 11 November 2026
The StatOps agent is installed on servers that host your clients’ sites. This page describes precisely what it does, so you can decide with full knowledge and check it yourself.
In one sentence
The agent reads some information about the server and sends it to StatOps. It will jamais run a command it receives: StatOps’ reply is not interpreted, and the agent opens no listening port.
What the agent reads
| Information | How |
|---|---|
| CPU, memory, load, disk space (excluding virtual file systems) | Reading the system counters, with no special rights. |
| Machine name, system, kernel, architecture, uptime | Reading the system counters. |
| Sites served by Nginx | Command nginx -T, which prints the full configuration. The agent extracts only the domain names and whether HTTPS is used; the rest of the output is discarded. |
| Sites served by Apache | Command {{ 'apachectl -S (or apache2ctl -S, httpd -S), which summarises the virtual hosts. The agent extracts only the domain names ({{ 'ServerName and ServerAlias) and port 443 as a hint of HTTPS. |
| Sites served by Caddy | Request {{ 'GET /config/ on Caddy’s admin API, which listens only on the machine (localhost:2019) and needs no special right. The agent extracts only the routes’ domain names and whether HTTPS is used. If Caddy does not respond, the source is simply ignored. |
| Docker containers and sites routed by Traefik | Commands {{ 'docker ps and docker inspect with a fixed format: name, image, state, start date, restart count, exit code and labels. Labels are used to read Traefik routing rules; only the domain names are kept. |
| Sites routed by Traefik, through its API | Request GET /api/http/routers on Traefik’s API, only at an address of the machine (localhost:8080 by default; any address other than localhost, 127.0.0.1 or [::1] is refused). The agent extracts only the domain names and whether HTTPS is used. If the API is not enabled, the source is ignored and Docker labels take over. |
| Sites published through a Cloudflare tunnel | Reading only the file /etc/cloudflared/config.yml (or config.yaml), directly or through {{ 'cat via the sudo rule below. The agent extracts only the lines hostname; the tunnel credentials and the rest of the file are discarded. No call to the Cloudflare API. |
| Pending system updates (Debian, Ubuntu) | Simulation apt-get -s dist-upgrade, with no special rights: nothing is downloaded or installed. The agent keeps only the number of updates, including security ones, and whether the file /run/reboot-requiredexists. Package names are not sent. |
The fixed format of {{ 'docker inspect asks for neither environment variables, nor secrets, nor container logs.
What the agent sends
One report per minute. Sites and containers are read at start-up, then every five minutes. The report contains the following, and nothing else:
- the agent version and the sending time;
- the machine: name, system, kernel, architecture, uptime;
- the measurements: CPU usage, used and total memory, average load, and for each disk its mount point, used space and total space;
- the sites discovered: domain name, source (Nginx, Apache, Caddy, Traefik or Cloudflare Tunnel) and whether HTTPS is used;
- the containers: name, image (for example registry/project:version), state and status;
- the pending updates: their number, the number of security updates, and whether a restart is needed;
- any discovery errors, as short text.
The agent does not read or send: the content of sites, files, databases, logs, environment variables, passwords, keys and certificates.
You can see the exact report before it is sent: the command statops-agent --dry-run prints it without sending anything.
These same readings feed the maintenance log: when pending updates are no longer pending, a server restarts or a container image changes, StatOps notes it in the log of the client concerned, which the agency reviews before the report is sent. No additional reading is done on the server.
One way only
- The agent contacts StatOps; StatOps never contacts the agent.
- StatOps’ reply is ignored on success: it cannot contain a command to run. No remote-control channel exists, and none is planned.
- Sends go over HTTPS. HTTP is accepted only towards the local machine.
- Each server has its own token, shown only once at creation and stored hashed on StatOps’ side. Deleting the server in the dashboard makes its token unusable, without touching the other servers.
- If StatOps is unreachable, the agent keeps the latest reports in memory (60 at most) and resends them on reconnection.
Rights requested on the server
- A dedicated system user,
statops-agent, with no command shell or home directory. The agent does not run as root. - No access to the Docker socket and no
{{ 'dockergroup (that group is equivalent to root). Discovery goes through asudorule limited to read commands:nginx -T,apachectl -S,docker ps -aq --no-trunc,{{ 'docker inspectwith its fixed format andcatof the Cloudflare Tunnel configuration file only. Any other call is refused. - This rule is shown during installation, checked by
visudo, and can be viewed withstatops-agent sudoers. - The systemd service isolates the
{{ '/homefolder and uses a/tmpprivate one.
Install, verify, uninstall
- Read the script before running it:
curl -fsSL https://get.statops.frprints it. It does only what is described at the top of the file. - The script checks the binary’s SHA-256 checksum before installing it. If
minisignis installed on the server, it also checks the signature with the public key below and stops if it is invalid. - The binaries are signed with minisign and you can check the signature yourself, before installing. Public key (ID
13188DBC96E98996):RWSWiemWvI0YE1iIC0ZTI8oxB3RsOVNVpjIgtHL8rnys8CB8H+b1pn9J. For an x86_64 server (replace with{{ 'aarch64otherwise):curl -fsSLO https://get.statops.fr/download/x86_64, thencurl -fsSL https://get.statops.fr/download/x86_64.minisig -o x86_64.minisig, thenminisign -V -m x86_64 -x x86_64.minisig -P RWSWiemWvI0YE1iIC0ZTI8oxB3RsOVNVpjIgtHL8rnys8CB8H+b1pn9J. The signed comment gives the version and architecture. - Uninstalling is one command:
{{ 'sudo sh -s -- --uninstallremoves the service, the binary, the sudoers rule, the configuration and the user. - Updating means running the install command again without a token: the script reuses the server’s own, replaces the binary, regenerates the sudoers rule and restarts the service.
Agent tests
The agent’s automated tests run 87.7% of its code (676 lines out of 771, not counting the test code itself). Measured on 7 November 2026 on version 0.1.1, with cargo-llvm-cov.
| Part of the agent | Code run by the tests |
|---|---|
| Reading the configurations (Nginx, Apache, Caddy, Traefik, Docker, Cloudflare Tunnel) | 95 to 100% |
| Sending to StatOps (HTTPS, queue during an outage) | 100% |
| System measurements (CPU, memory, disks) | 98% |
| Running the commands and chaining the discovery | 82% |
| Service start-up | 47% |
The rest is mostly the life of the service (sending every minute, clean shutdown) and cases that need a real web server installed. These cases were checked with real Nginx, Apache, Caddy and Traefik in Debian containers.
On StatOps’ side
- Two-factor authentication on the dashboard.
- Passwords stored hashed; two-factor authentication secrets and SMTP passwords stored encrypted.
- Limits on sign-in and sign-up attempts.
- Roles per organisation: owner, member, reader.
- Encrypted database backups, with restoration tested.
- Storage location, retention periods and processing: see the privacy policy.
What is not in place yet
In the interest of transparency, here are the current limits:
- Without
minisignon the server, the install script checks only the SHA-256 checksum, served by the same server as the binary. It detects corruption but does not protect against a compromised distribution server: install minisign or check the signature by hand, as described above. The private key is kept off the server. - There is no package repository yet (APT, RPM).
- The agent’s code is not published.
Report a security issue
If you think you have found a vulnerability, write to contact@statops.fr describing what you observed. Please do not make it public before we have been able to fix it.