Security
What goes into the sandbox, what never does, and the known limits.
Pistis treats everything in the sandbox as hostile: the repository, the model's commands and every dependency. A fully compromised sandbox should find none of your keys or tokens, and nowhere to send what it does hold (the repository) beyond the hosts you allow.
Two sides
The agent, the database, the web app, Slack and the HTTP API.
Everything inside it: the repository and any code the model runs.
Who can do what
PISTIS_SECRET_KEY; the sandbox gets no tokens and only connects out. Docker sits behind pistis docker-proxy.Every action in the web app and the API passes the policy, which refuses anything unclear (Roles). Secrets people enter are encrypted with PISTIS_SECRET_KEY. An MCP server imported with an agent stays off until an admin turns it on. Pistis reaches Docker only through pistis docker-proxy. Sandboxes and your own machines get no tokens and only connect out.
What goes into the sandbox
| Goes in | Never goes in |
|---|---|
| Commands, file edits and their output | Git, registry and API tokens |
| A copy of your repository | Repository URLs with tokens in them |
| A one-time join token | The conversation |
| Skill files the agent uses | Who started the session |
What comes out, command output and saved files, is treated as untrusted. Saved files have a size limit and are only ever unpacked inside a sandbox.
Every way out
| Path | What stops it |
|---|---|
| Into the sandbox | No open ports. On Docker, each sandbox has its own network, so sandboxes can't reach each other. |
| The internet | Whatever the sandbox provider allows, which is nothing by default (Network access). |
| Git | The sandbox has no git token, so it can't push. |
| Publishing work | The publish tool runs on your Pistis server, pushes one branch pistis/<session> and opens a pull request. It can wait for approval. |
| A crash | A command that may have partly run is never retried. |
Approvals
Tools you mark as risky wait for a person: the session's owner, or someone they shared it with as an approver. See Approvals.
Known limits
The model can be misled.
Text in the repository can steer the model, and the model can call any tool you gave it. Gate publish, and bash if you want to read every command.
Encrypted traffic to an allowed host passes unread.
The Docker allow list sees the host name, not the request. Code in the sandbox could hide data in a request to an allowed registry. Keep the list short.
A sandbox can lie about its own results.
Code in the sandbox controls what its commands print. Treat command output as untrusted. That's why approvals and publish run on your server.
Sandboxes can reach the relay service.
The relay is the service sandboxes connect to, so they must reach it. Every relay endpoint except a health check needs the admin key or that sandbox's own pass. Its state file holds hashed passes, never git or API tokens.
One admin key for the relay.
Your Pistis servers and the relay (the service sandboxes connect to) share one admin key, PISTIS_RELAY_KEY. Whoever holds it can do anything a Pistis server can do at the relay, so keep it with your other server secrets. If it leaks, set a new one on the relay and every server and restart them. A key per server is planned.
Docker allows about 30 networks by default.
With one network per sandbox, that caps how many sandboxes exist at once. Raise it with default-address-pools in Docker's daemon.json.
Network lock-down is the provider's job.
The sandbox must be unable to reach anything you didn't allow. Docker does this with a network per sandbox, Kubernetes with a NetworkPolicy. Don't run untrusted work on a provider that can't.