Skip to content

Security: EvoEvolver/treer

Security

docs/security.md

Security Model

Treer's current supported tier is trusted or mostly trusted machines and workspace members. It is not a safe multi-tenant execution sandbox.

Supported Claims

  • Machines enroll once, then authenticate with a workspace-bound credential.
  • Managed Agents have separate workload credentials, verified by both the Controller and Proxy and bound to one Agent, machine, and workspace.
  • An Agent can register or clear only its own Agent Interface Server. The Controller verifies the private-loopback manifest before advertising it and never forwards the workload credential to the interface. Its local recovery cache contains only a process-bound descriptor and is revalidated before use.
  • Agent-authenticated routes cannot create, update, or delete machine services, virtual hosts, or service ingresses. That denial is enforced before workspace Policy, so an old CLI cannot restore the capability. Agents may create Managed Apps; Core atomically owns those Apps' service and virtual-host records.
  • Local operator requests use a private Controller credential that is not injected into managed Agent environments.
  • Service tokens are short-lived and audience-bound. Human App token verification rechecks current workspace membership and service existence.
  • Core Message authorizes send, read, receive, ack, and operator import separately. Context edges do not expand visibility.
  • Message bodies stay out of ordinary logs, audit payloads, domain events, and outbox envelopes. They remain plaintext in Core PostgreSQL.
  • Organization and workspace management plus successful lifecycle mutations produce append-only audit events without prompts, terminal data, commands, or secrets.
  • Machine exec and file upload require current workspace access and distinct machine.exec / machine.file.write Policy actions. Their paths are confined beneath the enrolled Host root, and audit records omit command arguments, output, and file content.
  • An Agent may register, read, or clear only its own Host-restart startup spec. The Proxy applies distinct agent.startup.read and agent.startup.manage actions, and a restored process is launched only while its durable Agent credential remains active and bound to the same machine.

Unsupported Claims

Do not describe Treer as zero trust, mutually untrusted multi-tenancy, end-to-end encrypted from the Proxy, per-user provider credential isolation, or a filesystem sandbox. The current coding-agent launch modes can execute with the machine account's authority. Same-account processes may inspect files, process metadata, local configuration, or credentials available to each other. Machine exec and file upload are likewise not restricted administration APIs: they run or write with the Controller account's filesystem permissions. Host root containment prevents accidental path targeting outside the enrolled tree, not access that the same account can obtain through commands, symlinks, or other same-account processes.

Agent startup specs are an explicit persistence capability, not a sandbox or a reliable operating-system boot service. The machine-local private state file contains the startup argv and plaintext workload credential. Do not place secrets directly in argv; use files or a secret provider already protected for the machine account. Anyone with that account's authority can modify the same state or execute an equivalent command.

Apps do not create a security boundary. Managed Apps currently run through the same Host and sandbox backend as command Agents, under the installing machine account. Externally managed Apps inherit their supervisor's authority. Treer Policy limits what authenticated requests Core accepts; it cannot stop an App from using other same-machine credentials or services it can reach. Run untrusted code under a separate user, container, VM, microVM, or stronger sandbox.

Agent Interface Servers likewise do not create a security boundary. They run with the Agent's operating-system authority and may expose transcript and prompt operations to callers already authorized by Proxy Policy. Interface ports stay on Agent-private loopback; the Controller is the external routing and policy boundary.

Repository launchers are optional code executed with the Agent's operating- system authority. Treer's binary installer, updater, and release artifacts do not fetch or install them. The ACP launcher is obtained separately and performs builds only during an explicit apply.sh operation; ordinary Agent startup does not fetch or update software. Its headless profiles expose no browser path. Selecting the Remote Codex UI profile explicitly trusts and builds the immutable upstream commit recorded in the launcher lock file, then serves it only through the existing private Agent Interface tunnel.

The Create Agent dialog's one-click CLI installs execute cataloged third-party install scripts or package-manager commands with the machine account's authority. Treer does not mirror, pin, attest, or sandbox those upstream artifacts beyond the Agent runtime already described here. Treat the action as trusting that provider's current installer, and use a dedicated machine, VM, or stronger sandbox when that trust is not acceptable.

proxy-env is not a full traffic intercept. The injected HTTP CONNECT and SOCKS listeners classify destinations locally: workspace virtual-host names and the reserved local-API address stay on the Treer path; ordinary internet destinations are dialed on the machine and never wait on the Proxy. Linux transparent mode still captures all Agent TCP through the TUN. Do not describe macOS proxy-env as a forced proxy for GitHub or other public sites.

The opt-in native Mac network lab demonstrates PID capture into this existing virtual-host Policy/relay path. Its cooperative registration gate, shared DNS cache, upstream helper half-close behavior, and fail-open helper shutdown do not provide Linux namespace isolation or a new supported transparent mode. See the measured limits.

The owned native backend adds kernel audit token and process-birth validation, registration acknowledgement before exec, and a corrected directional TCP copier. Roots and observed descendants are checkpointed in provider-private storage and restored only for live process instances from the same system boot. The UDP adapter routes each target through Controller/Proxy authorization. It remains experimental: detached children before their first observed flow, protection during extension death, system virtual DNS and installed UDP capture still have open delivery gates. Unsigned builds and kernel identity unit tests do not establish an installed capture boundary.

Tracked network connections are periodically reauthorized, including Direct connections from Controllers that report their complete lifetime. A denial or reauthorization timeout closes the tracked connection. Five-second polling and the Policy cache mean revocation is not instantaneous. Older Direct Controllers continue to have Open-only authorization. Proxy-env internet bypass traffic is outside this mechanism.

New Controllers negotiate durable Direct usage receipts. Each receipt is issued only after Policy authorization and binds reports to the original workspace, machine, Agent and destination. Cumulative reports are checkpointed locally before transmission, and removed only after the Proxy commits deduplication state and both machine/Agent ledgers in one database transaction. Reports can arrive after revocation or reconnect; receipts authorize accounting only, never a new socket. Duplicate and older reports add nothing; mixed decreasing/increasing counters are rejected. Undelivered, unused receipts are discarded and remaining open receipts expire with the 90-day traffic retention window. Legacy peers retain best-effort, live-stream reporting.

Direct counters remain machine-reported observations with zero billable bytes. Abrupt crashes can lose bytes since the latest five-second checkpoint; delayed reports are bucketed at commit time. Disk/storage failures remain visible failures, not proof of complete accounting. Agent detail describes the same traffic and is not additional billable traffic. An Apple Developer account does not by itself supply complete detached-child tracking: Apple's optional Endpoint Security entitlement requires a separate request. That backend is not implemented or claimed here.

Credentials

Credential Scope and limit
Enrollment key One workspace, ten minutes, single use
Machine bearer credential One enrolled machine and workspace; long-lived until rotation/removal
Agent workload credential One managed Agent process; same-account inspection remains possible
Local operator credential One Controller install; protects the local API but is not a same-account sandbox
Workload identity token One Agent/machine/service audience for 60 seconds
Human App token One user/workspace/service audience; verification rechecks membership and service
Human user session Cookie treer_session for browsers; native iOS/Android also receive the same token in JSON when X-Treer-Client is exactly mobile, mobile_ios, or mobile_android. Authorization: Bearer is accepted on every user route. The header is not CORS-allowed. Do not put the token in query strings
Platform admin session Cookie scoped to /api/admin; separate from user accounts; can list emails and issue password-reset links
Updater token Shared Bearer secret between Proxy and the Compose updater sidecar; never exposed to browsers
Mail cookie Local opaque handle to an App token; compromise of Mail state grants that token until expiry
Voice ASR vendor key Proxy process only (TREER_VOICE_ASR_API_KEY / DASHSCOPE_API_KEY); never the iOS/Android app
Voice LLM vendor key Proxy process only (TREER_VOICE_LLM_API_KEY); used for utterance-to-command; never the phone
Telegram bot token One Telegram bot; Telegram and any process that can inspect it can act as the bot
Release signing key All official release manifests; must remain offline and outside runtime systems

Telegram numeric user/chat/topic allowlists are channel admission, not Treer authentication. Inbound Telegram Messages are authored by the authenticated bridge Agent and retain sender-asserted external metadata.

Data Exposure

Proxy and database operators can read Message bodies, recipients, context edges, and acknowledgement state. Deployments must manage PostgreSQL backups, retention, export, and deletion because Core does not yet expose those operator workflows.

Mail can read any body it renders or sends and stores pending PKCE state plus a cookie-to-token mapping in SQLite. Telegram can read bridged bodies and stores Bot API offsets, delivery hashes, errors, and external/Core ID mappings. App state and WAL files require normal credential-store protection and backup.

Public service ingress deliberately accepts anonymous internet traffic. Workspace ingress requires a current member session or service-audience token. For restricted workspaces, current membership means an effective direct or group workspace grant, workspace creation ownership, or organization manager access. Authorization is recalculated from PostgreSQL, and removing a user from the organization invalidates all workspace access. The Proxy strips gateway credentials and Treer headers before forwarding, but it remains in the browser-to-service data path. The Proxy records directional payload byte and frame totals for these tunnels under the synthetic browser client endpoint. Each aggregate carries a traffic class and meter version so future billing rules remain explainable; workspace members can read those aggregates. It does not store payload content, request paths, headers, or NATS control-plane traffic in the usage ledger.

Self-hosted Compose gives the updater sidecar the host Docker socket and a read-only bind of compose.yaml. Compromise of that sidecar is host Docker compromise. Proxy, App, PostgreSQL, and NATS do not mount the socket. Hosted Railway does not run the sidecar. /api/admin/update* require a current platform admin session; workspace members cannot start an image apply.

Linux publish_ports maps a namespace TCP port onto the machine loopback. It is not an internet listener. Any process on that machine that can reach 127.0.0.1 can reach the published service. Agent-scoped services use a separate Unix bridge into the same namespace and do not open a host TCP port. Managed Apps use publish_ports for their declared HTTP UI port, then route the stable service and virtual hostname to that loopback listener. When wildcard ingress is configured, Core creates a dedicated ingress for each Managed App. It uses workspace access by default, requiring a current workspace session or service-audience credential. An Agent may request public access only while creating a Managed App; that App then accepts anonymous internet requests and must implement any application-level authentication it needs. Their command, arguments, working directory, hostname, access choice, and public_url are plaintext Proxy metadata; the Managed App API deliberately has no secret field.

Only a logged-in workspace user or operator API may directly mutate service, virtual-host, and ingress records. Managed Agents can list or probe existing records for compatibility but cannot publish arbitrary sandbox listeners. Their only publication authority is the declared HTTP port of a Managed App created through the atomic App lifecycle.

Workspace members may change an existing Managed App's owned ingress between workspace and public access from the App settings UI. This endpoint resolves the ingress from the App record and does not accept a service, hostname, or arbitrary ingress identifier from the caller. An App selected as the active Policy Provider cannot be switched to public access.

Policy And Rollout

Policy is authoritative only after authentication establishes an immutable subject and resource scope. A workspace owner may delegate rules to a selected Managed App, but the Proxy retains authentication, scoping, runtime binding, Provider selection, and the typed cache-invalidation recovery path. Provider fetches are bounded loopback requests through the Controller, not arbitrary Proxy egress. A valid stale bundle is used only for the configured window; fail_closed is the default and fail_open is an explicit owner choice. A missing Provider and missing legacy workspace Policy currently defaults to the visible Treer Default monitor/allow baseline. The owner-only default App installer is a recovery path: it uses bounded machine uploads, private Managed App creation, protocol validation, and automatic Provider binding without consulting delegated Policy. It never downloads executable content on the machine. Monitor mode computes denials without enforcing them; decision audit is still absent. The Core Message feature flag is deployment sequencing, not a security control.

Hardening Order

  1. Replace allow-all defaults with reviewed policies and auditable decisions.
  2. Bind provider credentials and runtime actions to explicit owners.
  3. Add a real isolation backend for untrusted workloads and scoped secret delivery.
  4. Add credential rotation, retention/deletion workflows, quotas, and incident diagnostics.
  5. Enforce signed release manifests and downgrade protection in installed updaters.

Relevant source boundaries are crates/treer-proxy/src/auth.rs, identity.rs, policy.rs, message_store.rs, updater.rs, deploy/updater/updater.py, and the Controller sandbox and network modules.

There aren't any published security advisories