Security

The boundary is the product.

Shells exists so that code you don't fully trust — yours, your users', your agents' — can run somewhere with real walls. Here is exactly where those walls are.

Isolation you choose

Every shell declares its runtime class at create — capability-scoped wasm, namespace-isolated container, or hardware-virtualized microvm. The boundary matches the trust level of the code, not a one-size default.

Sealed by default

New shells get no network unless you say otherwise. internet and localhost are explicit modes — egress is a granted capability, never an accident.

Keystone service boundaries

Sessions, IAM, entitlements, and usage flow through Keystone (Auth v4 / IAM v4 / Garden v4). Every list is tenant-scoped; every action is permission-checked; OAuth scopes are enumerated, not wildcarded.

One gate for agents

Agent calls enter through POST /api/agent/invoke and clear two checks: the shells.agent.invoke entitlement and the underlying instance permission. There is no second, quieter door.

Credentials with a half-life

Term credentials are minted per session, expire in minutes, and are rendered masked in the console. Agents and humans re-mint instead of storing.

Redacted activity history

The activity terminal records that a credential mint happened — never the material. Scrollback is redacted at the source, so secrets can't be scraped from history.

Credentials

Masked until you ask. Gone in minutes.

Live-session credentials are the most attackable artifact a sandbox product produces. Ours are short-lived by construction, masked by default, and recorded as events — not values — in the activity history.

Masked term credentials dialog with expiry notice

Scope, exactly

What the console is allowed to do.

The OAuth scope set for shells.sh is enumerated and product-shaped. This is the entire list — no admin scopes, no wildcards.

keystone client — shells.sh
# identity
openid profile email offline_access
# platform
auth:session · iam:read · garden:usage:write
# product
shells:instances:read
shells:instances:create
shells:instances:control
shells:agent:invoke

Honest about logs

Execution logs are fetched on demand through the lifecycle action API — you pull them when you need them, and the pull itself is recorded in the activity terminal. We'd rather tell you exactly how it works than wave the word "real-time" at you.

Disclosure

Found something? We want it fixed more than you do. Write to security@shells.sh and you'll get a human response — typically within one business day — and credit if you want it.