npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

opencode-sandbox

v0.3.0

Published

OpenCode plugin that sandboxes agent commands using @anthropic-ai/sandbox-runtime (seatbelt on macOS, bubblewrap on Linux)

Downloads

318

Readme

CI npm version License: MIT

opencode-sandbox

An OpenCode plugin that sandboxes agent-executed commands using @anthropic-ai/sandbox-runtime.

Every bash tool invocation is wrapped with OS-level filesystem and network restrictions — no containers, no VMs, just native OS sandboxing primitives.

| Platform | Mechanism | |----------|-----------| | macOS | sandbox-exec (Seatbelt profiles) | | Linux | bubblewrap (namespace isolation) | | Windows | Not supported (commands pass through) |

Install

// opencode.json
{
  "plugin": ["opencode-sandbox"]
}

The plugin is automatically installed from npm when OpenCode starts.

Linux prerequisites

1. Install bubblewrap:

# Debian/Ubuntu
sudo apt install bubblewrap

# Fedora
sudo dnf install bubblewrap

# Arch
sudo pacman -S bubblewrap

2. Ubuntu 24.04+ (AppArmor fix):

Ubuntu 24.04 and later restrict unprivileged user namespaces via AppArmor, which prevents bubblewrap from working. You need to enable the bwrap-userns-restrict AppArmor profile:

# Install the AppArmor profiles package
sudo apt install apparmor-profiles

# Create the symlink to enable the profile
sudo ln -s /etc/apparmor.d/bwrap-userns-restrict /etc/apparmor.d/force-complain/bwrap-userns-restrict

# Load the profile
sudo apparmor_parser -r /etc/apparmor.d/bwrap-userns-restrict

You can verify bwrap works:

bwrap --ro-bind / / --dev /dev --proc /proc -- echo "sandbox works"

Without this fix, bwrap will fail with loopback: Failed RTM_NEWADDR: Operation not permitted or setting up uid map: Permission denied.

What it does

When the agent runs a bash command, the sandbox enforces three layers of protection:

Filesystem write protection

Commands can only write to the project directory and /tmp. Writing anywhere else returns "Read-only file system":

$ touch ~/some-file
touch: cannot touch '/home/user/some-file': Read-only file system

$ echo "data" > /etc/config
/usr/bin/bash: line 1: /etc/config: Read-only file system

Sensitive file read protection

Access to credential directories is blocked:

$ cat ~/.ssh/id_rsa
cat: /home/user/.ssh/id_rsa: Permission denied

Network allowlist

Only approved domains are reachable. All other traffic is blocked via a local proxy:

$ curl https://evil.com
Connection blocked by network allowlist

$ curl https://registry.npmjs.org
(works — npmjs.org is in the default allowlist)

Default restrictions

Filesystem (deny-read):

  • ~/.ssh, ~/.gnupg
  • ~/.aws/credentials, ~/.config/gcloud
  • ~/.npmrc, ~/.env

Filesystem (allow-read):

  • Empty by default

Filesystem (allow-write):

  • Project directory
  • Git worktree (validated — unsafe paths like / are rejected)
  • /tmp

Network (allow-only):

  • registry.npmjs.org, *.npmjs.org
  • registry.yarnpkg.com
  • pypi.org, crates.io
  • github.com, *.github.com
  • gitlab.com, *.gitlab.com
  • api.openai.com, api.anthropic.com
  • *.googleapis.com

Everything else is blocked by default.

Configuration

Config files are stored outside the project directory (in ~/.config/opencode-sandbox/) so that sandboxed commands cannot modify them. This prevents indirect prompt injection from weakening the sandbox by overwriting the config.

Config file locations

The plugin searches for configuration in this order (first match wins):

  1. Environment variable OPENCODE_SANDBOX_CONFIG (JSON string)
  2. Per-project config ~/.config/opencode-sandbox/projects/<project-name>.json
  3. Global config ~/.config/opencode-sandbox/config.json
  4. Built-in defaults

The <project-name> is the basename of the project directory (e.g., my-app for /home/user/projects/my-app).

If XDG_CONFIG_HOME is set, it is used instead of ~/.config.

Example: Global config

// ~/.config/opencode-sandbox/config.json
{
  "filesystem": {
    "denyRead": ["~/.ssh", "~/.aws/credentials"],
    "allowRead": ["~/.ssh/id_ed25519.pub"],
    "allowWrite": [".", "/tmp", "/var/data"],
    "denyWrite": [".env.production"]
  },
  "network": {
    "allowedDomains": [
      "registry.npmjs.org",
      "github.com",
      "*.github.com",
      "api.openai.com",
      "api.anthropic.com",
      "my-internal-api.company.com"
    ],
    "deniedDomains": ["malicious.example.com"]
  }
}

Path precedence

Path precedence is inherited from @anthropic-ai/sandbox-runtime:

  • Read: allowRead takes precedence over denyRead
  • Write: denyWrite takes precedence over allowWrite

Example: allow git commit signing with SSH public key

If your Git workflow needs to read a public key (for example ~/.ssh/id_ed25519.pub) while keeping ~/.ssh blocked by default, re-allow only that file:

// ~/.config/opencode-sandbox/config.json
{
  "filesystem": {
    "denyRead": [
      "~/.ssh",
      "~/.gnupg",
      "~/.aws/credentials",
      "~/.azure",
      "~/.config/gcloud",
      "~/.config/gh",
      "~/.kube",
      "~/.docker/config.json",
      "~/.npmrc",
      "~/.netrc",
      "~/.env"
    ],
    "allowRead": ["~/.ssh/id_ed25519.pub"]
  }
}

Example: Per-project config

// ~/.config/opencode-sandbox/projects/my-app.json
{
  "network": {
    "allowedDomains": ["my-internal-api.company.com"]
  }
}

Environment variable

OPENCODE_SANDBOX_CONFIG='{"filesystem":{"denyRead":["~/.ssh"]},"network":{"allowedDomains":["github.com"]}}' opencode

Example allowing only the SSH public key to be read:

OPENCODE_SANDBOX_CONFIG='{"filesystem":{"denyRead":["~/.ssh","~/.gnupg","~/.aws/credentials","~/.azure","~/.config/gcloud","~/.config/gh","~/.kube","~/.docker/config.json","~/.npmrc","~/.netrc","~/.env"],"allowRead":["~/.ssh/id_ed25519.pub"]}}' opencode

Disable

OPENCODE_DISABLE_SANDBOX=1 opencode

Or in any config file:

{
  "disabled": true
}

How it works

The plugin uses two OpenCode hooks:

  1. tool.execute.before — Intercepts bash commands and wraps them with SandboxManager.wrapWithSandbox() before execution
  2. tool.execute.after — Restores the original command in the UI (hides the bwrap wrapper)
Agent → bash tool → [plugin wraps command] → sandboxed execution → [plugin restores UI] → Agent

The AI model interprets sandbox errors (like "Read-only file system" or "Connection blocked") directly from command output — no additional annotation layer needed.

Fail-open design

If anything goes wrong (sandbox init fails, wrapping fails, platform unsupported), commands run normally without sandbox. The plugin never breaks your workflow.

Contributing

See CONTRIBUTING.md for development setup, architecture, and guidelines.

Related