# Threat model

> Review assets, adversaries, trust assumptions, and mitigations.

Canonical page: https://docs.tentaflake.dev/security/threat-model/

> Source: [`docs/15-threat-model.md`](https://github.com/timfewi/tentaflake/blob/e21be475a3afc6e95c5087003edd0b7f780e4df4/docs/15-threat-model.md) at `e21be475a3af` · docs version **0.4.37**

This document defines the security model for a tentaflake host running
long-lived, potentially compromised AI agents. It describes the intended
boundaries of the generic template. A deployment fork must add a target-host
review, credential inventory, tailnet policy, provider policy, and recovery
evidence.

## Security objective

The `balanced` profile assumes that prompts, retrieved content, dependencies,
and the agent process can become hostile. Compromise of one controller should
not by itself grant access to host secrets, another agent, direct Internet or
LAN egress, a privileged container runtime, or an unrestricted host shell.
Required external access is mediated by narrow host services. Risky local code
execution is delegated to a disposable, offline worker.

The `dev` profile is a compatibility mode, not a security boundary. The
`strict` profile fails evaluation because a tested separate-kernel boundary is
not yet implemented. There is no silent downgrade to either profile.

## Assets

The model protects:

- the host kernel, NixOS configuration, boot state, container engine, and
  system services;
- operator access, tailnet identity, and recovery authority;
- provider, Git, backup, signing, and deployment credentials;
- agent workspaces, broker audit records, backups, and operational logs;
- other agents and their state, credentials, budgets, and broker endpoints;
- external provider accounts, repositories, websites, and cost budgets;
- the integrity and availability of the declarative configuration and pinned
  software artifacts.

## Adversaries and failure modes

The design considers:

- prompt injection or malicious model output controlling an agent;
- hostile documents, websites, repositories, packages, and generated code;
- a compromised or malicious controller image or dependency;
- attempts to escape a container, abuse a Linux capability, exhaust resources,
  scan local networks, reach metadata services, or steal runtime credentials;
- cross-agent access, broker impersonation, SSRF, DNS rebinding, redirect
  abuse, request smuggling through oversized inputs, and cost exhaustion;
- unauthorized Git pushes or external side effects;
- a remote attacker reaching an accidentally published management service;
- operator error, stale backups, policy drift, storage exhaustion, service
  crash loops, and incomplete monitoring;
- supply-chain substitution of a mutable or unauthorized container image.

Denial of service against the whole host through a kernel, storage, container
engine, or hardware failure is reduced but not eliminated.

## Trust assumptions

The following remain trusted computing base or operator assumptions:

- the physical machine, firmware, host kernel, NixOS closure, systemd, Nix
  evaluation, and the operator account;
- the selected Docker or Podman engine, gVisor `runsc`, firewall, filesystem,
  and their correct activated configuration;
- the deployment fork's runtime secret provisioning and file ownership;
- reviewed image-signing identities and keys when provenance enforcement is
  enabled;
- correct provider, repository, backup, tailnet, DNS, and alerting policy owned
  outside this generic template;
- operators review the exact build and target before activation and perform
  real restore and incident-response drills.

An image digest gives reproducible identity, not trust. Cosign verification
shows only that the configured signer authorized that exact artifact. Neither
claim proves that the software is benign.

## Trust boundaries and data flows

### Operator to host

Management enters through the operator account and an explicitly installed
tailnet grants/SSH policy. Tentaflake does not publish its CLI or observability
listeners to a public interface. Tailscale transport alone is not authorization,
and the template cannot verify the remote control-plane policy.

### Host to controller capsule

The host starts a digest-pinned controller with `runsc`, a non-root user, no
added capabilities, a read-only root filesystem, bounded resources, selected
AppArmor/Seccomp policy, and only declared mounts. Secure profiles reject host
networking, published ports, extra devices, unconfined overrides, sensitive
mounts, mutable image tags, and direct provider credential files.

Caller-supplied host user-namespace overrides are rejected. The current
root-managed Docker/Podman paths do not prove daemon-level host UID remapping:
Docker remapping would change every persistent bind-mount owner, and Podman's
`keep-id`/`nomap` modes are rootless-only. `runsc` and the non-root container
UID are enforced boundaries; separate host UID mapping remains an explicit
residual risk until an ownership migration and both runtime paths are tested.
The pinned Podman/runsc VM also reports no AppArmor profile and incomplete
capability metadata; the security doctor treats the absent profile as critical.
Host AppArmor enablement alone is not proof of that capsule's confinement.

The controller workspace is persistent and writable. An optional exact-size
filesystem bounds that workspace, and an optional separate filesystem bounds
private runtime state. The controller may still corrupt or delete its own
data. Other state and aggregate sparse-image allocation need host capacity
policy; individual quotas do not reserve free space for every agent.

### Controller to external services

A balanced controller either has `network=none` or joins one agent-specific
internal bridge. Research-enabled agents use only that agent's host LLM broker
on the bridge; legacy fetch is rejected. Deterministic interface and source-subnet firewall rules reject
forwarding and unrelated host services. The controller receives only a
runtime virtual key, never the upstream credential.

The LLM broker enforces exact routes and models, clamps completion size, and
applies concurrency, rate, token, and cost budgets. It rejects provider-hosted
tools and known web extension fields; operators must select inference-only
models. [Web research](https://docs.tentaflake.dev/configuration/research/) uses a per-agent Unix socket capability
and the public isolated service. Each relay has a distinct host UID even when
container UIDs match. Only its exact socket directory and client closure are
projected read-only; gVisor can open these sockets but cannot create host sockets.
VPN readiness, public-address checks, budgets and worker isolation constrain
research egress. These controls do not make retrieved content safe to execute
or trust, or prevent disclosure of text supplied to an allowed remote service.

Each broker process has
systemd memory/task/file ceilings. Optional aggregate admission checks count
LLM and fetch separately for concurrency and request rate. The credential
setup unit has no capabilities and uses an explicitly read-only broker parent
with one writable agent directory. It preserves its virtual key across unit
restarts. These host controls preserve the existing
provider-credential boundary; they do not add a new external integration.

### Controller to disposable worker

The worker receives a bounded, descriptor-safe workspace snapshot and runs a
short-lived `runsc` capsule with no network or secrets. It returns artifacts
through a controller-specific read-only import. Only `local-reversible`
actions run automatically; other permitted classes wait for a host-side
approval record, and `forbidden` is rejected.

This boundary cannot prove that every tool exposed by every upstream agent
runtime routes shell or file work through the worker. Runtime-specific tool
configuration remains a deployment review item. Approval also does not grant
network access or implement a generic external-action adapter.

### Host to external systems

Git auto-push, backups, provider access, signature verification, remote
tailnet policy, and alert delivery execute with host-held authority. Their
credentials remain runtime files or systemd credentials. Each integration
must be narrowly scoped by the deployment: exact repository and branch,
provider account and models, backup repository, signer identity, tailnet
grants, and alert receiver.

### Telemetry and detection

Systemd journals are the primary local audit trail; there is no custom SQLite
audit database or web console. The optional Alloy/Loki/Prometheus/Grafana
profile is loopback-only and supplies baseline metrics and rules. The separate
Falco profile detects selected runtime behavior but does not prevent it.
Retention, off-host evidence, notification delivery, and sensitive-log review
remain deployment responsibilities.

## Control and evidence map

| Risk | Primary control | Required evidence |
|---|---|---|
| Host or peer access | gVisor capsule, mounts, capabilities, firewall | eval, build, live inspect, negative VM test |
| Direct egress | internal per-agent bridge and broker-only rules | activated firewall plus DNS/LAN/metadata tests |
| Credential theft | host-held credentials and virtual broker key | generated unit and live mount/environment review |
| SSRF and rebinding | fetch allowlist, public-IP checks, pinned DNS | broker tests and target-host broker health |
| Cost exhaustion | rate, concurrency, token, and cost budgets | policy review, audit output, alerts |
| Unsafe code execution | disposable offline worker and approval classes | queue, timeout, cleanup, and no-egress tests |
| Unauthorized Git write | exact remote and branch host helper | denial tests and least-privilege credential review |
| Mutable image substitution | digest pin and optional Cosign start gate | verified policy plus failed-signature start test |
| Resource exhaustion | memory, CPU, PID, tmpfs, log, and workspace limits | live limits and exhaustion tests |
| Lost state | encrypted Restic policy and success freshness | real fresh-host restore drill |
| Runtime anomaly | journald, optional observability and Falco | retention, receiver, and response drill |
| Remote management exposure | loopback listeners and tailnet policy template | live listeners and remote policy audit |

Source inspection proves intended code. Nix evaluation proves option types and
assertions. A successful build proves the closure. VM tests prove only their
fixture. Activation changes a particular host. Live inspection and adversarial
tests are required before calling that host secure. Unavailable AF_UNIX,
container-inspect, tailnet, broker, backup, or alert evidence is unknown, never
green.

## Explicit non-goals and residual risks

Tentaflake does not:

- make Docker, Podman, gVisor, the kernel, firmware, or hardware immune to
  vulnerabilities;
- provide a tested MicroVM or separate-kernel `strict` profile today;
- attest that a signed image, model, dependency, website, or generated artifact
  is safe or correct;
- prevent an agent from damaging its own writable workspace;
- transparently mediate every tool in every supported upstream agent runtime;
- provide generic adapters for arbitrary purchases, messages, deployments, or
  other external side effects;
- configure production tailnet grants, provider accounts, registry trust,
  backup storage, Grafana retention, Alertmanager delivery, or off-host logs;
- guarantee availability under host-wide storage, kernel, engine, network,
  power, or hardware failure;
- replace patch management, key rotation, capacity planning, incident response,
  or human review of requested actions.

Falco and observability improve detection. Backups improve recovery. Neither is
a preventive isolation boundary. A deployment must document accepted residual
risks and the owner of every external control before unattended operation.

## Deployment acceptance checklist

Before treating a host as ready for unattended agents:

1. Keep every untrusted controller on `balanced`; confirm `strict` still fails
   closed and document any deliberate `dev` exception.
2. Review generated units, exact mounts, identities, resource limits, image
   digests, provenance policies, and agent-specific broker policy.
3. Build and run the unit, module-evaluation, and VM suites without activating
   the production host as a side effect.
4. Review and separately approve the exact host activation.
5. Run `tentaflake doctor --security`, live OCI inspection, listener checks,
   and direct-egress, LAN, metadata, peer, and broker negative tests.
6. Audit the deployed tailnet grants/SSH policy and all external credentials
   for least privilege and rotation.
7. Configure log retention, capacity alerts, notification delivery, and an
   operator response path; validate them end to end.
8. Perform a real encrypted backup and fresh-host restore drill.
9. Record remaining unknown evidence and accepted residual risks. Do not count
   a warning or unavailable check as a pass.
