Security: agent binary updates have no cryptographic signing - compromised server can push arbitrary root-level code
What is the installation method of your PatchMon server?
Docker
What is the version of your PatchMon server?
2.0.2
Briefly describe the feature
Agent binary signing: prevent compromised server from pushing arbitrary root-level code via auto-update
Detailed description
Summary
The agent auto-update mechanism verifies downloaded binaries using a SHA256 hash, but both the binary and the hash are served by the same PatchMon server. The hash check protects against transmission errors and MITM attacks on the wire, but provides no protection if the PatchMon server itself is compromised or malicious.
Because the agent runs as root and accepts executable updates over persistent connections, a compromised server can push a modified binary with a matching hash and achieve full root-level code execution on every enrolled host.
Background
This was acknowledged in the v1.3.0 release notes:
"I plan to use PGP for signing agents off in the future and improve security mechanisms for server/agent verification."
Technical detail
There are actually two independent code paths that trigger an agent update, both without signature verification:
Path 1 - WebSocket command (serve.go):
The server can send update_agent or update_notification { "force": true } over the persistent WebSocket connection.
Path 2 - HTTP report response (report.go):
After every periodic report, the server response is checked for AutoUpdate.ShouldUpdate. If true, updateAgent() is called immediately and silently, without any explicit command.
Both paths call the same updateAgent() in version_update.go:
GET /api/v1/hosts/agent/version- server returns{ version, hash }GET /api/v1/hosts/agent/download- server returns binary- Agent checks
sha256(binary) == hash- if match, installs and restarts
Since hash and binary both originate from the same server, an attacker with server access can serve malicious_binary + sha256(malicious_binary). The integrity check passes and the binary is installed as root on all connected hosts.
Impact
Threat | Protected? |
|---|---|
Wire corruption / transmission error | ✅ Yes |
MITM on the network connection | ✅ Yes (TLS + hash) |
Compromised PatchMon server (container breakout, stolen credentials, supply chain) | ❌ No |
Insider with server admin access | ❌ No |
The severity is elevated because: (a) the agent runs as root, (b) the update can be triggered remotely without interaction on the managed host, and (c) there are two trigger paths, one of which fires automatically on every report cycle.
Proposed solution
Implement code signing for agent binaries using an asymmetric key pair:
- Developer signs each release binary with a private key (e.g.
cosign,minisign, or GPG detached signatures). - Public key is embedded in the agent binary at build time.
- Agent verifies the signature against the embedded public key before installing any update. A valid signature requires the private key, which is never on the server.
For self-hosted deployments where operators build their own binaries, the signing key should be configurable: the operator generates a key pair, embeds the public key at build time, and signs their own releases with the private key.
Why is this useful?
The agent runs as root and accepts binary updates from the PatchMon server. Currently, update integrity is verified only via SHA256, where both the hash and the binary are served by the same server. A compromised server can therefore push a malicious binary with a matching hash and gain root-level code execution on all enrolled hosts. This was acknowledged in the v1.3.0 release notes ("I plan to use PGP for signing agents off in the future") but has not been implemented. Code signing with an embedded public key would break this trust dependency.
0 Comments
Sign in to comment
No comments yet. Be the first to share your thoughts!
