Known security gaps
For: cluster operators and plugin authors.
Known gaps
Management holds the CA
Management apart can act as anyone. It holds the CA. The signing command moves the CA's key out of it; nothing yet stops a management that is taken from issuing certificates while it is.
Tier 0 has no sandbox
Tier 0 has no sandbox. Nodes without bubblewrap or Seatbelt, and Windows nodes, run plugins with the node's user's rights.
Jobs that outside input started run only on tier-1 nodes: where the tenant has none for the work, the edge refuses the start rather than run it at tier 0.
A harness session that can run a shell or write files never falls back: it runs on a tier-1 node, whoever started the job, or on a node a tenant admin opted out of tier 1 on purpose, with a reason, as a reviewed change; that node is a finding while it holds it, and every job that used it shows tier 0, so the gap is one an admin chose for one machine and can see, not a default (the sandbox opt-out).
A tier-0 node is a health finding with its fix, so it does not stay one unnoticed; the install scripts set up bubblewrap and, on Ubuntu, Ubuntu's own AppArmor profile for it. Check the installed version against the bubblewrap advisory and protected-path requirements; a distribution's latest package can still be too old.
Nodes can read their tenant's payloads
A node sees its whole tenant. The content permission is enforced in the APIs; a node of the tenant can read any of its tenant's payloads. Give tenants that must not see each other's data separate tenants, not labels.
Webhooks reveal whether a trigger exists
Webhooks say whether a trigger exists. An unknown flow or routine answers 404, an existing one without its secret 401, whether or not that secret is set yet.
Object checks in the authorization matrix
The authorization matrix tests calls with real objects, including rollouts, kill switches and budget requests. It compares a caller's response for another tenant's object with the response for an absent object. See what the authorization tests cover.
API keys after a person's removal
A tenant can keep a removed person's API keys working. API keys belong to their tenant and record who created them. Removing an account (oz0 account remove, oz0 user remove) revokes the keys it created, by default. A tenant that set oz0 tenant removed-account-keys <tenant> finding keeps them working instead, listed in a health finding until an admin revokes each one with oz0 apikey revoke <id>. Removing only a person's role in a tenant leaves their account, and the keys they made, in place: oz0 apikey list --tenant <tenant> shows each key's creator.
Identity tokens outside the cluster
Identity tokens are bearer tokens outside the cluster. A service that receives one cannot tell whether the caller is the node the call ran on; the token is short and names one audience, which is what limits it. A verifier that caches the issuer's key set for longer than an hour may still trust a key an emergency rotation dropped until its cache ends.
Loopback MCP client identity
Loopback MCP clients can be impersonated. A client that registers with a loopback redirect address is whatever program listens there; the consent page says so, and PKCE keeps a code useless to a program that did not start the flow. Tenants that want only named clients turn loopback off and list client hosts.
Backdoored models
A backdoored model is not detected; it is bounded. A model's weights can be edited, an abliteration that strips its refusals, a fine-tune, a merged adapter, to behave normally until a trigger it was given appears, and then to drive a session to fetch a script, run it unread, read secrets and send them out.
Orchestrator Zero does not inspect model weights for backdoors. The sandbox bounds what the session does with it: at tier 1 the fetch and the exfiltration are refused by the egress proxy and audited, the session reads only its job's directories and holds no provider key (and no plugin secret in a job an outside event started, as the plugin-secret boundary describes), and a kill switch stops it; a tier-0 shell or write session has none of this (above).
Pinning a model by its digest pins its integrity, not its trust, it proves the weights are the ones you pinned, not that anything in them is safe, and no runtime stops a coding model, backdoored or not, from writing a subtle flaw into code a person later merges; the approvals and the evals help a person catch it (Security).
Limits of strict budgets
A strict budget bounds what a provider's published prices and a call's own limits bound. A tool's price, a tier's multiple, what one tool use adds to the input and what one image adds are data: where a provider changes a price, or a search brings back more than the figure a record holds, a call can pass its reservation by that difference, and the charge records what the provider reported. Next to that, the provider bills by its own account of a call, which the gateway reads and cannot check.
Provider models and hosted tools
What a provider's own models and tools do is the provider's. The gateway reads what a call's body names: it refuses a stored object the record does not vouch for, an address outside the tenant's egress list, and a hosted web tool the tenant did not turn on. It cannot see past that.
It refuses the model families it knows to search by name until a tenant turns hosted web tools on, and a model outside that list that searches or browses by itself reaches what the provider lets it reach.
A hosted tool a tenant turned on, or a remote MCP server on the list, can carry what a job read to wherever the model points it. Text in a prompt can ask a provider's tool to do the same. The tenant's data rules decide which providers are trusted that far.
With provider_state: own, a cluster admin's word decides whose objects a tenant's calls can read: an account that is shared after all reads as the tenant's own, and only the key's hash can contradict it, and only when the two tenants use the very same key.
The word ends with the record's key, though only as far as a change shows: an outside store that replaces a value without a new version does not end it.
Shared hosts and encrypted tunnels
An allowed shared host is its provider. The egress proxy checks a tunnel's visible TLS server name without decrypting it. A tunnel to an allowed CDN or ECH provider's host can reach another of that provider's customers, through the encrypted HTTP Host header or a client's own Encrypted Client Hello configuration whose public name is the allowed host.
A /tcp entry for such a host goes further: the proxy reads only a tunnel's first bytes, so a later request in plain text is not read either. Allow shared hosts only when you must, and put a mirror on the tenant's list for a package host behind one.
The operator's HTTP proxy
Through the operator's HTTP proxy, the proxy decides. A node fetches a URL a plugin chose (a harness's binaries) from public addresses only, checked where the node connects. When the operator sets HTTPS_PROXY, the node checks the addresses the name resolves to before it uses the proxy, but the proxy resolves the name again and connects where its own rules let it; the SHA-256 pin still decides what the node runs. Give the proxy rules that refuse internal destinations.
Plugin source fetches
An edge fetches plugin sources where its rule allows. A Git source, a registry, an index, a marketplace's entries and the URLs a plugin's content names are fetched from public addresses over HTTPS, and from the private networks the operator listed (server start --plugin-source-allow-net), never from the edge's own machine (any address of its interfaces, inside a listed network too), its link or a cloud's metadata service; git is held to the addresses its host was checked at and follows no redirect. Through the operator's HTTP proxy, as on nodes, the proxy has the last word.
Independent security review
Orchestrator Zero has had no independent security review or penetration test.