Security model¶
CAESAR controls a real home. The security posture is conservative on
purpose — and concrete: this page describes what's actually wired,
not aspirations. The
security-review track (the SR-NNN items
referenced below) is the operative record of what's been hardened
and what's still open.
Trust boundaries¶
HTTP clients External LLM APIs
(phone, browser, (data egress hazard;
n8n, webhook senders) keys held only by Praetor)
│ │
│ bearer (SR-001) │ HTTPS to provider
▼ ▼
┌────────────────────────────────────────────────┐
│ Praetor │
│ trusted; the only component that holds │
│ long-lived secrets (LLM keys, HA token, │
│ dashboard token, NKEY seed) │
└─────┬──────────────────┬──────────────┬────────┘
│ │ │
│ REST + WS │ NATS │ HTTPS
│ (HA token) │ (optional) │
▼ ▼ ▼
Home Assistant Legion pool ntfy.sh
(in-process +
plugins +
remote workers
with per-NKEY auth)
Authentication, per surface¶
| Surface | Default | Hardening |
|---|---|---|
/v1/chat, /v1/devices |
Loopback bind, open to localhost | CAESAR_SERVER__API_TOKEN ⇒ bearer-token required (SR-001 fu). Startup logs a warning if you bind non-loopback without a token. |
/v1/hook/{trigger_id} |
— | Per-trigger bearer token (ADR-0032); 64 KiB body cap; rate-limited cooldown. |
/dashboard/* |
Returns 404 until token is set | CAESAR_DASHBOARD__TOKEN enables it; signed session cookie; per-cookie revocable records (SR-007 fu); optional separate signing key (SR-006). |
/metrics |
Open; loopback-bound by default | CAESAR_METRICS__TOKEN ⇒ bearer-token required (SR-003). |
| NATS bus (Legion) | Disabled | When enabled, opt into per-identity NKEY auth via CAESAR_BUS__AUTH__ENABLED (ADR-0027). Per-worker subject scopes documented in RUN-A-WORKER. |
| HA Bridge | Disabled until URL + token are set | Long-lived HA token, treated as a high-value secret. |
Principles¶
- One credential vault. Only Praetor holds long-lived secrets (HA token, LLM provider keys, dashboard token, NKEY seed). Workers run in-process under Praetor (sharing its credentials) or on other hosts with their own NKEY seed (which authenticates them on the bus but doesn't grant access to LLM or HA credentials).
- Side effects are mediated. Every HA service call and every
Legion tool call passes through the Policy Engine (ADR-0013 +
ADR-0028). Plugin tools ride the same
allowed_toolsallow-list as in-tree tools — no plugin can call anything an operator hasn't explicitly permitted. - Declarative policy. Operators describe what's allowed in
policy.yaml; the engine evaluates per call. New rules don't require a code release. - Decisions are auditable. Every brain decision lands in
audit_logwith the inputs that produced it. Plugin loads, tool calls, policy denials, trigger fires — all recorded with stable event-type codes for grepping. See ADR-0012. pip installis the trust act for plugins. Plugins (ADR-0035) run same-process with Praetor. CAESAR doesn't sandbox them — installing a plugin is the same trust act as adding a Python dependency. Operators paranoid about the surface can pin to an explicit allow-list viaCAESAR_PLUGINS__ALLOWLIST.
Threat model¶
| Threat | Mitigation |
|---|---|
Network-adjacent attacker hits /v1/chat |
Loopback default; CAESAR_SERVER__API_TOKEN required for LAN exposure (SR-001 fu). |
| Webhook URL leaks | Per-trigger bearer (Authorization: Bearer …) constant-time-compared; 64 KiB body cap; cooldowns coalesce repeats. |
| Dashboard cookie is exfiltrated | 7-day TTL by default; revocable per-cookie session records (SR-007 fu); signing key can be rotated independently of the auth token (SR-006). |
| LLM is prompt-injected via a tool output | Tool outputs are passed as ToolResult blocks, not free-text injected into system prompts; policy gates every subsequent action. |
| HA token is exfiltrated by a worker | Workers (in-process and remote) never see the HA token. All HA traffic goes through Praetor's bridge. |
| LLM API key is exfiltrated by a worker | Same. Workers never see provider keys; they go through the LLMGateway Praetor owns. |
Malicious plugin is installed via pip |
Trust posture matches the rest of pip install: review the package first, pin versions, verify Sigstore attestation when published with Trusted Publishers (SR-011 fu). CAESAR_PLUGINS__ALLOWLIST pins the surface. The Policy Engine still gates every tool call regardless of plugin claim. |
| Compromised remote worker host | Per-identity NKEY auth (ADR-0027) — workers can only publish/subscribe to their declared subject scopes. A stolen seed lets an attacker impersonate one worker, not the whole pool. |
LAN-adjacent attacker scrapes /metrics |
Loopback by default; CAESAR_METRICS__TOKEN for LAN exposure (SR-003). |
| Supply-chain compromise of a transitive dependency | Pinned versions; dependency-review CI job; Dependabot PRs with the auto-merge gate held for security alerts. |
| Pathological audit-log payload bloats the table | Per-string clamp at write time (CAESAR_MEMORY__AUDIT_MAX_STRING_CHARS, default 16 KiB; SR-008). |
| Audit log eventually fills the disk | TTL retention sweeper (ADR-0020) deletes rows older than CAESAR_MEMORY__RETENTION_DAYS. |
| Operator's policy is misconfigured | YAML parsed at startup, not first-call; bad rules fail loud. Audit log surfaces every policy decision for review. |
Out of scope¶
- An attacker with root on the host running Praetor. Self-hosted
homelab software cannot help here. CAESAR-side hardening guidance
(loopback bind, secret-manager-over-
.env, regular backup) is in CONFIGURATION.md and OPERATIONS.md. - Defending against a malicious operator. CAESAR trusts its owner.
- Sandboxing plugins. Subprocess- and container-isolated plugin models were considered and rejected for v2.0 — see ADR-0035 §Alternatives. Operators who want isolation should run CAESAR itself in a container with whatever filesystem and network restrictions match their threat model.
Reporting issues¶
See SECURITY.md — use GitHub's private vulnerability reporting, not public issues.
Track record¶
SECURITY-REVIEW.md lists every SR-NNN
finding from the v1.0 security review (ADR-0025), its status, and
the PR that closed it. New findings get tracked the same way.