Security fixes are made against the latest release. Please run a current version before reporting.
Please do not open a public issue, PR, or discussion for security vulnerabilities.
Report privately via GitHub's "Report a vulnerability" (Security → Advisories) so we can triage and fix before disclosure.
Please include: affected version, a description and impact, and steps to reproduce (redact any tokens, credentials, or hostnames).
We aim to acknowledge reports within a few days and will coordinate a fix and disclosure timeline with you.
Automated scanners flag RemotePower for sudo usage. That flag is accurate, and
it is worth being explicit about where privilege is actually held, because the
answer is narrower than "the whole thing runs as root".
The server does not run as root. The app server, scheduler and push daemon
run as the web-server user — www-data on Debian/Ubuntu, nginx on RHEL,
http on Arch — under NoNewPrivileges=true, ProtectHome=true and
PrivateTmp=true, with ProtectSystem=full on the app server and scheduler
and the stricter ProtectSystem=strict on the push daemon, which needs nothing
writable at all. Nothing in the web tier — the API, the UI, the dashboard you
log into — holds root.
Two ambient capabilities are the exception worth naming, because "unprivileged"
should not be read as "no capabilities at all". The app server and the scheduler
hold CAP_NET_RAW, which is what lets them ping an agentless device for
reachability, and CAP_NET_ADMIN, which is what reads WireGuard peer statistics
directly when RP_WG_DIRECT is set. An install that uses neither agentless
reachability nor the WireGuard Access page can delete the AmbientCapabilities=
line from both units and lose nothing else.
The agent runs as root, by design. Applying a patch, restarting a unit or
reading SMART data is what the agent is for: dpkg / pacman / systemctl /
smartctl cannot be driven usefully without privilege. An unprivileged agent
would be a monitoring product that cannot remediate, which is a different
product. The trade is made on purpose, and constrained:
- Every subprocess uses the argv-list form — no shell interpolation, so
there is no injection surface — with one exception: the
exec:command channel, which is the operator-facing "run this command on that host" feature and is authenticated, authorised and audit-logged as such. - Agent state lives in
/var/lib/remotepower/at mode0700, enrollment credentials at0600, written atomically withO_NOFOLLOWon every read and write to defeat symlink attacks from local non-root users. - TLS verification is mandatory (
CERT_REQUIRED+check_hostname), and the agent never follows HTTP redirects — it posts its own token, so a3xxmust never be replayable to another host. - Self-updates are SHA-256 verified and applied atomically. Setting
/etc/remotepower/require-signed-updatesmakes the agent fail closed: it will refuse any update that is not signed by a pinned release key. Release tarballs carry a detached GPG signature, and the container images are signed with cosign keyless signing — verify with both--certificate-identity-regexpand--certificate-oidc-issuer, since a barecosign verifyproves only that something signed the image, not who. - The systemd unit adds
PrivateTmp,ProtectKernelTunablesandProtectControlGroups. It does not setProtectKernelModules— that directive hides/usr/lib/modulesfrom the unit, so a package upgrade that rebuilds the initramfs produced an image with no kernel modules in it and left the host unbootable (fixed in v6.2.1).
sudo in the install scripts is installation-time only. Creating a service
user, writing unit files and installing packages need it; the running services
do not re-acquire it.
Credentials, where they are stored, and their file modes are enumerated in
docs/security.md.
RemotePower's security model, SSRF protections, CSP posture, and the per-release
security reviews are documented in docs/security.md.