See how OpenShell's network policy system works in under five minutes. You'll create a sandbox, watch a request get blocked by the default-deny policy, apply a fine-grained L7 rule, and verify that reads are allowed while writes are blocked — all without restarting anything.
- A running OpenShell gateway (
mise run gateway:dockerfor local development) - Docker daemon running
| File | Description |
|---|---|
policy.yaml |
L7 read-only policy for the GitHub REST API, scoped to curl |
demo.sh |
Automated script that runs the full walkthrough non-interactively |
openshell sandbox create --name demo --no-auto-providers--no-auto-providers skips the provider setup prompt since this
demo doesn't use an AI agent.
You'll land in an interactive shell inside the sandbox:
sandbox@demo:~$
curl -s https://api.github.com/zenThe request fails. By default, all outbound network traffic is denied.
The sandbox proxy intercepted the HTTPS CONNECT request to
api.github.com:443 and rejected it because no network policy authorizes
curl to reach that host.
curl: (56) Received HTTP code 403 from proxy after CONNECT
Exit the sandbox (sandboxes are kept running by default; pass --no-keep at creation time to delete on exit):
exitopenshell logs demo --since 5mYou'll see a line like:
action=deny dst_host=api.github.com dst_port=443 binary=/usr/bin/curl deny_reason="no matching network policy"
Every denied connection is logged with the destination, the binary that attempted it, and the reason. Nothing gets out silently.
Review the policy:
cat examples/sandbox-policy-quickstart/policy.yamlversion: 1
# Default sandbox filesystem settings.
# These filesystem fields are required when using `openshell policy set`
# because it replaces the entire policy.
filesystem_policy:
include_workdir: true
read_only: [/usr, /lib, /proc, /dev/urandom, /app, /etc, /var/log]
read_write: [/sandbox, /tmp, /dev/null]
landlock:
compatibility: best_effort
network_policies:
github_api:
name: github-api-readonly
endpoints:
- host: api.github.com
port: 443
protocol: rest
tls: terminate
enforcement: enforce
access: read-only
binaries:
- { path: /usr/bin/curl }The top section preserves the default sandbox filesystem and Landlock
settings while omitting process identity so the active compute driver can
select it. These settings are required because policy set replaces the
entire policy.
The network_policies section is the interesting part: curl may make
GET, HEAD, and OPTIONS requests to api.github.com over HTTPS.
Everything else is denied. The proxy terminates TLS (tls: terminate)
to inspect each HTTP request and enforce the read-only access preset
at the method level.
Apply it:
openshell policy set demo \
--policy examples/sandbox-policy-quickstart/policy.yaml \
--wait--wait blocks until the sandbox confirms the new policy is loaded.
No restart required — policies are hot-reloaded.
openshell sandbox connect democurl -s https://api.github.com/zenAnything added dilutes everything else.
It works. Try a more visual endpoint:
curl -s https://api.github.com/octocat MMM. .MMM
MMMMMMMMMMMMMMMMMMM
MMMMMMMMMMMMMMMMMMM ____________________________
MMMMMMMMMMMMMMMMMMMMM | |
MMMMMMMMMMMMMMMMMMMMMMM | Speak like a human. |
MMMMMMMMMMMMMMMMMMMMMMMM |_ ________________________|
MMMM::- -:::::::- -::MMMM |/
MM~:~ 00~:::::~ 00~:~MM
.. MMMMM::.00:::+:::.00teleMMM ..
.MM::::: ._. :::::MM.
MMMM;:::::;MMMM
-MM MMMMMMM
^ M+ MMMMMMMMM
MMMMMMM MM MM MM
MM MM MM MM
MM MM MM MM
.~~MM~MM~MM~MM~~.
~~~~MM:~MM~~~MM~:MM~~~~
~~~~~~==googler======~~~~~~
~~~~~~==googler======
:MMMMMMMMMMM:
'=googler=='
curl -s -X POST https://api.github.com/repos/octocat/hello-world/issues \
-H "Content-Type: application/json" \
-d '{"title":"oops"}'{"error":"policy_denied","policy":"github-api-readonly","detail":"POST /repos/octocat/hello-world/issues not permitted by policy"}The CONNECT request succeeded (api.github.com is allowed), but the L7
proxy inspected the HTTP method and returned 403. POST is not in
the read-only preset. Your agent can read code from GitHub but cannot
create issues, push commits, or modify anything.
Exit the sandbox:
exitopenshell logs demo --level warn --since 5ml7_decision=deny dst_host=api.github.com l7_action=POST l7_target=/repos/octocat/hello-world/issues l7_deny_reason="POST /repos/octocat/hello-world/issues not permitted by policy"
The log captures the exact HTTP method, path, and deny reason. In production, pipe these logs to your SIEM for a complete audit trail of every request your agent makes.
openshell sandbox delete demo| State | What happens |
|---|---|
| Default deny | All outbound traffic blocked — nothing gets out |
| L7 read-only | GET to api.github.com allowed, POST blocked |
| Audit trail | Every request logged with method, path, decision |
The policy hot-reloads in seconds and gives
you verifiable, fine-grained control over what your agent can access —
without --dangerously-skip-permissions.
- Customize the policy: Change
access: read-onlytoread-writeor add explicitrulesfor specific paths. See the security policy reference. - Scope to an agent: Replace the
binariessection with your agent's binary (e.g.,/usr/local/bin/claude) instead ofcurl. - Add more endpoints: Stack multiple policies in the same file to allow PyPI, npm, or your internal APIs.
- Try audit mode: Set
enforcement: auditto log violations without blocking, useful for building a policy iteratively.