Pistis

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

Trusted: your Pistis server

The agent, the database, the web app, Slack and the HTTP API.

Untrusted: the sandbox

Everything inside it: the repository and any code the model runs.

Who can do what

Peoplebrowser · tokens Policyevery action Your server · trusted Pistis serverencrypted secretsrecord of what ran MCP serversoff until an adminenables it docker-proxyPistis's containers only Docker Trust boundary · nothing crosses with a token Sandboxno tokens Your machineone pool relayservice dials out
Three lines: the policy checks every action and refuses anything unclear; secrets stay on your server, encrypted with 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 inNever goes in
Commands, file edits and their outputGit, registry and API tokens
A copy of your repositoryRepository URLs with tokens in them
A one-time join tokenThe conversation
Skill files the agent usesWho 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

PathWhat stops it
Into the sandboxNo open ports. On Docker, each sandbox has its own network, so sandboxes can't reach each other.
The internetWhatever the sandbox provider allows, which is nothing by default (Network access).
GitThe sandbox has no git token, so it can't push.
Publishing workThe publish tool runs on your Pistis server, pushes one branch pistis/<session> and opens a pull request. It can wait for approval.
A crashA 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.

On this page