PiMonitor is currently pre-1.0. Security fixes are provided for the latest release only; there is no long-term support branch at this stage.
| Version | Supported |
|---|---|
| latest | yes |
| < latest | no |
Please report security vulnerabilities using GitHub Security Advisories for this repository rather than opening a public issue. This allows a fix to be prepared and released before the details become public.
If GitHub Security Advisories are not available to you, open an issue with minimal detail asking for a private contact channel, and a maintainer will follow up.
Please include:
- A description of the vulnerability and its potential impact
- Steps to reproduce (Pi model, OS/distribution, PiMonitor version)
- Any relevant logs or configuration (with secrets/API keys redacted)
We aim to acknowledge reports within a few days and to release a fix as soon as reasonably possible depending on severity.
These notes summarize the security-relevant design decisions in PiMonitor so reporters and reviewers have context:
- The main
pimonitorservice runs unprivileged, as a dedicated system user with no special capabilities. It only reads world-readable files under/proc,/sys/class/thermal,/etc/os-release, and the existing apt cache under/var/lib/apt/lists/(via the read-onlyapt list --upgradablecommand). It never invokes anything that requires root. - Only apt cache refresh runs as root, via a separate, narrowly-scoped
systemd timer/service (
pimonitor-apt-update.timer) that runs exactly one command (apt-get update) on a schedule. This unit performs no other action and is not reachable from the web-facing service. - The HTTP dashboard and REST API are intended for trusted local networks
by default (no authentication, plain HTTP). If you expose the API to other
systems (e.g. for home automation integrations), set the optional
api_keyconfiguration value to require a bearer token on/api/v1/...requests (and onGET /metrics, ifprometheus_enabledis set), and do not expose the service directly to the public internet without TLS and additional access control, either via a reverse proxy or by setting the optionaltls_cert/tls_keyconfiguration values to have the service terminate TLS itself. The bundled dashboard keeps working withapi_keyset: it prompts for the key once per browser and persists it inlocalStorage(an accepted trade-off — anyone with access to the browser profile can read it, and without TLS the key is visible on the wire either way). - Supply the API key through the config file or the environment, not the
command line.
/etc/pimonitor/config.yamlis kept at mode640 root:pimonitorbyinstall.sh; alternatively setPIMONITOR_API_KEY, which systemd can load from anEnvironmentFile=with equally restricted permissions. The-api-keyflag is a development convenience only: a process's command line is world-readable via/proc/<pid>/cmdline, so a key passed that way is exposed to every local user on the machine. - Shell-outs (
apt list --upgradable, optionalvcgencmd measure_temp) are invoked with fixed argument lists (no user input is interpolated into shell commands), to avoid command injection. - Shell-outs are also invoked with an explicit, minimal environment rather
than inheriting the service's own — neither
aptnorvcgencmdneeds anything beyondPATH(and, forapt, a couple of apt-specific variables), soPIMONITOR_API_KEYis never copied into a child process's/proc/<pid>/environ. config.Loadcallsos.Unsetenv("PIMONITOR_API_KEY")immediately after reading the variable, so nothing later in thepimonitorprocess itself (a future code path, a library,os.Environ()) can read the key back out of the environment. This does not scrub the key from/proc/<pid>/environ. We verified this rather than assuming it: on Linux, that file is generated by the kernel once, from the rawargv/envpblock captured at the process'sexecve(), and is never regenerated from latersetenv/unsetenvcalls —os.Unsetenvonly updates the Go runtime's in-process copy of the environment. A local user who can already read/proc/<pid>/environfor thepimonitorprocess (in practice, root or thepimonitorservice user) can recover the key from it for the life of the process regardless of this call. The meaningful protections remain the ones above: keepapi_key/PIMONITOR_API_KEYout of the command line and in files with restricted permissions (mode640 root:pimonitor, asinstall.shsets up), and rely on the explicit subprocess environment (not this unset) to keep the key out ofapt's andvcgencmd's own environments.- Requests to any endpoint behind
apiRoute(every/api/v1/...route, plusGET /metricswhenprometheus_enabledis set) share a concurrency limit (withMaxInFlight,internal/httpapi/middleware.go), so a request flood — from another device on the LAN, a misconfigured integration, or a buggy retry loop — is bounded rather than able to multiply CPU/memory work without limit on constrained hardware such as a Pi Zero. This does not require authentication and is not a substitute forapi_key; it is a resource- exhaustion mitigation, not an access control. Seedocs/API.md.
If you believe any of these assumptions are violated by the current implementation, please report it as described above.