Skip to main content

Security Model

The CLI is an execution edge, not an authority. Every property below is enforced by the server or by a check the CLI cannot skip, and each maps to a command you can run to see it.

Credential absence​

The CLI holds no signing secret. A lease is an HMAC-signed token the server issues on claim and verifies again on POST /cli/claim/<leaseId>/verify before anything runs; the CLI only decodes the payload to read the act axes after that round trip succeeds. There is no configuration that lets vagaris dev spawn without a verified lease, and no local path that mints one.

Deny by default​

A lease without a tool policy means no tools, and a none policy refuses the spawn. Claude Code is launched with --allowedTools derived from the lease and never with claude --dangerously-skip-permissions; Codex is launched with codex --tool. Unknown adapters are refused rather than run unbounded. See Permissions.

Privileged acts never happen locally​

Pushing to a main branch, deploying, writing to a production database, mutating infrastructure, reading a secret or changing billing are brokered: the CLI sends a request, the server executes, approves, parks or denies, and the CLI reports the verdict. No local credential exists for these classes.

Machine identity​

vagaris node enroll generates an Ed25519 key pair; the private key is written to ~/.vagris/node-identity.json (mode 0600) and never sent anywhere. vagaris node doctor proves possession by signing a server nonce. A lease bound to a node is refused from any other node; vagaris node revoke invalidates the node's leases and cancels its runs server-side. See Node Enrolment.

Containment of the executor​

  • Worktree isolation. Each run executes in its own git worktree, removed afterwards.
  • Environment sanitising. Before the spawn, the child environment is stripped of product variables, LD_*/DYLD_*, GIT_CONFIG_*, NODE_OPTIONS and other interpreter and shell startup hooks, infrastructure write tokens and seat-forbidden inherited secrets. The keys removed are listed in the dev report as strippedEnvKeys.
  • Kill-switch integrity. runctl cancel reports cancelled only when the server has confirmed the process is dead. A run whose process survived the kill attempt is shown as still running — never a false stop.

Evidence​

Every governed run records session boundaries, policy decisions (with the gate that made them), baseline probes, the executed command and its output, scope requests and errors into an evidence envelope the server can audit. dev prints the counts and the closure-gate verdict.

Credentials on your machine​

  • Board login tokens are stored in the OS credential store (macOS Keychain via security, Linux Secret Service via secret-tool); ~/.vagris/auth.json holds only metadata. Without a credential store, a login is used for the current command and not persisted, and the CLI says so.
  • vagaris auth logout revokes server-side before deleting locally. vagaris uninstall does the same before removing files.
  • Agent API keys are printed once by vagaris agent local-cli. Prefer context set --api-key-env-var-name over writing a key into the context file.
  • The .env next to the instance config (which holds PAPERCLIP_AGENT_JWT_SECRET) is written with mode 0600.

Writing into other tools' directories​

The CLI never writes into ~/.claude or ~/.codex unless you pass --install-skills to vagaris agent local-cli and consent (interactively, or with --yes). What it wrote is recorded, and vagaris uninstall lists those links and leaves them in place rather than deleting inside another tool's home.

Support bundles and telemetry​

vagaris support-bundle passes every field through a redactor: vendor API keys, tokens, connection strings, PII and raw customer content are replaced with stable [REDACTED:kind:hash] placeholders; environment variables are included by name only; source code and database rows are never collected. See Support.

Telemetry is anonymous usage data, disabled by VAGARIS_TELEMETRY_DISABLED=1 (legacy PAPERCLIP_TELEMETRY_DISABLED=1), by DO_NOT_TRACK=1, automatically in CI, or by telemetry.enabled: false in the instance config.

Known limits​

  • Revoking a node changes server state; a process already running on that node stops the next time it contacts the server, not at the moment of revocation.
  • Leases have a bounded lifetime, but an expired lease is refused on verification rather than swept proactively.
  • The MCP server ships with a stdio transport; there is no HTTP MCP endpoint to expose.

The full threat model with per-control status lives in the repository at doc/security/threat-model-cli.md.

Reporting a vulnerability​

Use the repository's GitHub Security Advisory form — never a public issue. Details on Support.