Argos is a single-operator homelab panel. The threat model covers:
External attackers reaching published hosts from the internet.
Credential-stuffing / brute-force attempts against the panel login itself.
Compromise of a single dependency (an OIDC IdP, an upstream service, the SMTP relay used for notifications).
Outside the model:
A compromised host OS or docker daemon. If the attacker is root on the VM, game over — the master key is in .env, the DB is one file, all secrets decrypt.
A physical attacker with console access.
Multi-operator threat models (insider risk across admins). There is only one admin tier; the model assumes everyone with a panel login is trusted equally.
DoS at the network layer. Argos does per-IP rate limiting at the application layer; volumetric floods are the host provider / router's problem.
flowchart LR
subgraph internet[Untrusted]
attacker[Attacker]
idp[OIDC IdP]
crowdsec_hub[CrowdSec community hub]
dbip[DB-IP mirror]
end
subgraph trusted[Trusted]
caddy[Caddy]
crowdsec[Local CrowdSec]
argos[argos panel]
db[(SQLite)]
master[master key in env]
end
attacker --> caddy
caddy --> argos
idp -.->|OAuth tokens| argos
crowdsec -.->|LAPI decisions| caddy
crowdsec_hub -.->|community feed| crowdsec
dbip -.->|mmdb files| argos
argos --- db
argos --- master
Boundary 1 — internet <> Caddy. TLS at the edge, ACME for certs. CrowdSec bouncer drops known-bad IPs before any other handler.
Boundary 2 — Caddy <> argos. Docker bridge only; argos never exposed to the public internet in behind_caddy mode. In lan mode, argos IS reachable on the LAN -- treat the LAN as trusted.
Boundary 3 — argos <> OIDC IdP. Tokens validated against issuer's JWKS; state + nonce + PKCE prevent code-injection attacks.
Boundary 4 — argos <> master key. Env-only. Never on disk inside the image.
Every query in the codebase is parameterised; the only fmt.Sprintf into SQL is VACUUM INTO '<os-generated-path>' which cannot embed user input.
Path traversal in file ops
Backup file handling uses filepath.Join + explicit prefix check; restore extracts only within /data.
Audit log bypass
Every mutation runs through h.audit or h.Audit.Record. Verified by the fix(security) commit that backfilled missing audit fields.
DoS via memory-growing feature
PendingStore + TOTPStore sweepers cap memory; rate limit bucket map bounded by channel count; log ingestor uses a non-blocking channel that drops on saturation rather than grow.
Things the panel does NOT protect against and it is up to the operator to mitigate:
Loss of ARGOS_MASTER_KEY. Every encrypted secret becomes unrecoverable. Keep the key in a password manager independent of the panel.
Compromise of the host. Root on the VM means the attacker reads the env file, the DB, and the master key. Use a minimal LXC / VM with only argos on it; do not run argos on the same host as untrusted workloads.
Backup integrity. Argos records SHA-256 but does not sign. An attacker with write access to /data/backups/ can swap in a malicious archive that the restore path will extract. Protect the backup directory at the filesystem level.
External IdP compromise. If Google / Microsoft / Authentik is compromised, argos accepts tokens the attacker mints. Break glass: oidc.enabled=false disables the SSO path; local admin
TOTP still work.
Caddy admin API. Reachable only over the docker bridge but still unauthenticated. A container escape could reconfigure the edge. Mitigate via container hardening (no --privileged, read-only mounts where possible).