Skip to content

Agent Payload Signing

Since the hardening round of May 2026, each agent signs its ingest payloads with an own Ed25519 keypair. The hub-side bearer-token alone is not sufficient to push data on behalf of an agent — the attacker also needs the private signing key of the host.

Agent (first start)
├─ generates Ed25519 keypair
├─ writes secret to /var/lib/monsys/agent-signing.key (mode 0600)
└─ sends public key to hub via /api/v1/agents/register
Hub pins the key in
agents.signing_pubkey
(trust-on-first-use)
Agent (each ingest)
body = "[{...metrics...}]"
sig = base64(Ed25519(SHA256(body)))
HTTP POST /api/v1/ingest
Authorization: Bearer ms_...
X-Monsys-Signature: <sig>
Hub
pubkey = SELECT signing_pubkey FROM agents WHERE token_hash = …
if pubkey NULL → accept + log "unsigned_payload" (medium)
if sig missing → 403 + log "unsigned_payload" (high)
if sig invalid → 403 + log "signature_invalid" (critical)
otherwise → ✓ process
PlatformPath
Linux/var/lib/monsys/agent-signing.key
WindowsC:\ProgramData\monsys\agent-signing.key

Permissions on Linux: mode 0600, owner = the user running the agent (user/monsys depending on your install). Windows: ACL restricted to SYSTEM + Administrators.

Content is 32 bytes (raw Ed25519 secret seed). No header, no PEM — keep the file exactly that size.

The first time an agent sends a pubkey in register, the hub pins it and sets signing_set_at = NOW(). From then on, the pin is immutable from the agent — a new pubkey will be rejected and generates a signature_invalid integrity-anomaly.

To rotate legitimately, an admin must explicitly unset the pin via:

POST /api/v1/agents/<id>/rotate-signing-key

(see Token rotation)

What an attacker with only the bearer token cannot do

Section titled “What an attacker with only the bearer token cannot do”
AttackBlocked by
Fake metrics push under same agentsignature mismatch → 403
Honeypot trip falsificationsignature mismatch → 403
Process DNA hash replacementsignature mismatch → 403
Version downgrade in reportingsignature mismatch → 403, plus version_downgrade integrity check

What an attacker with token + key file can do

Section titled “What an attacker with token + key file can do”

If both are stolen, the attacker can fully report on behalf of the agent. The key file is however outside /etc/ (where system-config backups typically go), and is mode 0600. Concrete measures to prevent both from leaking together:

  • Keep the key file out of backups (backup_exclude in restic / borg)
  • Rotate the signing-key after a confirmed security event
  • Monitor changes on /var/lib/monsys/agent-signing.key with the host’s own FIM (auditd, auditctl -w /var/lib/monsys/agent-signing.key -p wa)

An older agent without signing module will continue to work: the hub accepts the unsigned payload but makes a unsigned_payload-anomaly every hour so it doesn’t go unnoticed.

Upgrade path:

Terminal window
# On the host
sudo apt update && sudo apt upgrade monsys-agent
# Or via install script:
curl -fsSL https://get.monsys.ai/install.sh | sudo bash
sudo systemctl restart monsys-agent

The agent then generates a keypair, registers the pubkey, and the unsigned_payload-anomalies are automatically closed in the next integrity cycle (10 min).