Skip to content

Security Model

shipking-ai edited this page Sep 3, 2026 · 1 revision

Security Model

This is the same content as SECURITY.md in the repo, kept here too because a wiki is where people look for reference material. If the two ever drift, the repo file is the one GitHub's own reporting flow points at, so treat it as current.

Reporting

Use private vulnerability reporting. It's enabled on this repository, so the report stays between you and the maintainers until there's a fix. Please don't open a public issue for anything exploitable.

Include what you did, what happened, and what you expected. A failing test is the fastest possible report.

What this thing is

An agent harness runs a language model's decisions as commands on your machine. It reads and writes files, runs shell commands, and talks to whatever MCP servers you have configured. The security posture is about bounding that, not eliminating it. Anyone running it should understand that the model chooses the actions and the harness decides which of them are allowed.

In scope

These are guarantees. If you can break one, that's a vulnerability.

  • Workspace confinement. Filesystem tools can't read or write outside the workspace root. The check follows symlinks — on existing paths and on paths about to be created — and resolves the root the same way it resolves the target. (This one shipped broken on macOS for several releases: the root was never resolved through symlinks while the target was, so /var/private/var meant every path looked like an escape. Fixed, and CI now runs the suite on macOS.)
  • Credential isolation. No subprocess inherits OMNIROUTE_API_KEY, OMNIROUTE_MGMT_TOKEN, OMNIHARNESS_API_KEY, or ROUTER_API_KEY. That list can't be disabled from config.
  • The policy gate. A tool whose risk class is configured ask doesn't run without approval; block doesn't run at all. An unrecognised risk class requires approval rather than defaulting to allow. An approval that times out, errors, or has no UI attached is a denial. Critical-risk tools are refused outright and can't be downgraded to a prompt.
  • shell_allowed = false means no shell, including by way of another tool.
  • Cost and token budgets stop a run at the ceiling — including a run that would exceed it inside a single turn, which is the case that's easy to get wrong.
  • The local HTTP API (omniharness serve) rejects any request carrying an Origin header or a non-loopback Host, so a web page can't drive it through DNS rebinding.
  • Secrets in the interface. An API key entered in the TUI is masked to its last four characters and never written to the transcript, the event log, or the session store.

Known and out of scope

Stated plainly, because a limitation you know about is a decision and one you don't is a trap.

Third-party credentials reach subprocesses. GITHUB_TOKEN, AWS_SECRET_ACCESS_KEY, NPM_TOKEN, and the rest are inherited by design — an agent asked to open a pull request or publish a package needs them. Strip them with policy.secret_env:

[policy]
secret_env = ["GITHUB_TOKEN", "AWS_*", "*_TOKEN"]

MCP tool descriptions are prompt injection. An MCP server describes its own tools, and those descriptions go to the model as instructions. A hostile server can say anything. Sanitising doesn't fix this — it's a property of the protocol. Run MCP servers you trust. A server can't take over a built-in tool by claiming its name — that's enforced and tested — but it can still lie about what its own tools do.

A model can be talked into things. The policy gate constrains what a tool may do, not what the model may be persuaded to want. Content the agent reads — a file, a web page, a tool result — can carry instructions. That's why the gate sits on tools rather than on intent.

--yes and bypass mean what they say. Both disable the approval prompt. They're for sandboxes and CI, not a workstation with credentials on it.

The default cost ceiling is $5, not zero risk. It bounds a runaway loop; it doesn't make the harness free.

Versions

Fixes land on main and publish immediately. There's no backport branch — the supported version is the latest release.

Clone this wiki locally