[FEATURE] Linux (bwrap): Add allowUnixSockets / allowAllUnixSockets equivalent for seccomp BPF

Status Open
Maintainer reply None cached
Activity 6 comments · opened Apr 6, 2026

Problem

On macOS, allowAllUnixSockets: true and allowUnixSockets path arrays exist to selectively permit AF_UNIX socket operations within the sandbox. On Linux (bwrap + seccomp BPF), no equivalent configuration exists. The seccomp filter unconditionally blocks all socket(AF_UNIX, ...) syscalls with EPERM.

This breaks any tool that requires Unix domain sockets for IPC:

  • Playwright / Puppeteer — Chromium requires AF_UNIX for Zygote/Mojo IPC → socket() failed: Operation not permitted (1)
  • SSH agentssh-add cannot connect to agent socket
  • GPG agentgpg-agent cannot create/connect to sockets
  • .NET MSBuild — worker nodes use AF_UNIX for IPC (#39257)

Context

  • This worked before v2.1.92 because the apply-seccomp binary was not bundled (#28576). The v2.1.92 changelog explicitly states: "Linux sandbox now ships the apply-seccomp helper in both npm and native builds, restoring unix-socket blocking for sandboxed commands."
  • macOS has had allowAllUnixSockets since sandbox-runtime PR #140 (2026-02-19), and path-scoped allowUnixSockets is being worked on (#41817).
  • Linux has no equivalent — the seccomp BPF filter is binary: all AF_UNIX blocked or none blocked.
  • excludedCommands only bypasses filesystem restrictions, not seccomp (#10524).
  • settings.json seccomp configuration is silently ignored (#24238).

Environment

  • Linux (WSL2), Claude Code v2.1.92+
  • sandbox.enabled: true

Reproduction

# Inside Claude Code sandbox:
python3 -c "import socket; s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)"
# → OSError: [Errno 1] Operation not permitted

# Chromium launch:
playwright-cli open https://example.com
# → FATAL: socket() failed: Operation not permitted (1)

Proposed Solution

Add Linux equivalents of the macOS socket configuration:

// settings.json
{
  "sandbox": {
    // Option 1: Allow all AF_UNIX sockets (parity with macOS)
    "allowAllUnixSockets": true,
    
    // Option 2: Path-scoped (preferred, more granular)
    "allowUnixSockets": [
      "/tmp/claude/**"
    ],
    
    // Option 3: Command-scoped seccomp exceptions
    // (extend excludedCommands to also bypass seccomp)
    "excludedFromSeccomp": ["playwright-cli", "chromium"]
  }
}

Any of these would unblock browser automation, SSH signing, and GPG operations on Linux.

Related Issues

  • #11791 — Browser automation incompatible with sandbox
  • #41817 — Path-scoped Unix socket bind() support (macOS)
  • #39257 — macOS sandbox blocks bind() for child processes
  • #41254 — allowAllUnixSockets does not cover network-bind
  • #24238 — seccomp config silently ignored
  • #28576 — apply-seccomp binary bundling (the fix that caused this regression)
  • OpenAI Codex PR #12702 — Fixed equivalent network-bind issue in their sandbox

View original on GitHub ↗

5 Comments

Logopher · 4 months ago

Adding a concrete use case and reproduction as a data point for prioritization.

Use case: signed git commits from a sandboxed session via host-side ssh-agent.

Setup: long-running ssh-agent on the WSL2 host with a signing key loaded, listening on /tmp/claude/vigil-signing.sock. Settings export SSH_AUTH_SOCK into the session and list the socket in sandbox.network.allowUnixSockets:

"sandbox": {
  "network": {
    "allowUnixSockets": ["/tmp/claude/vigil-signing.sock"]
  }
}

Inside the sandbox:

$ ls -l $SSH_AUTH_SOCK
srw------- 1 grault grault 0 Apr 15 03:08 /tmp/claude/vigil-signing.sock
$ ss -xl | grep vigil-signing
(no matches)
$ ssh-add -L
Error connecting to agent: Operation not permitted

The socket node is visible with correct ownership/mode, but connect(2) fails with EPERM and no listener exists in the sandbox — consistent with seccomp blocking AF_UNIX connect() unconditionally before netns or filesystem rules apply.

Why the feature matters here: signed commits are a security property that gets weakened if the signing step has to be carved out of the sandbox via excludedCommands or if the agent has to be run inside the sandbox (losing key isolation between sessions). A working allowUnixSockets on Linux would let the sandbox remain strict-by-default while still letting git commit -S reach a host-held key.

Docs note: the current sandboxing page documents allowUnixSockets and lists socat as a Linux install dependency without a platform-specific caveat. Users on Linux/WSL2 will reasonably expect it to work and won't know to look at this feature request until they hit the silent no-op. A short platform note on the docs page linking here would save downstream users the same debugging path.

Environment: WSL2, kernel 6.6.87.2-microsoft-standard-WSL2, Ubuntu 24.04, bubblewrap 0.9.0, socat installed, Claude Code 2.1.109.

GiGurra · 3 months ago

please add this :)

ulises-c · 3 months ago

It would be nice to be able to run sandbox and have ssh and gpg signing

BenWhetton · 2 months ago

Bump! This would be very useful to me also.

jmaccoby · 2 months ago

I spent a while researching how the Linux sandbox could get the path-selective allowUnixSockets
behavior macOS already has, and ended up building two of the options. Sharing the map in case it's
useful — full writeup + runnable code here: https://github.com/jmaccoby/unix-socket-allowlist-sandbox.

Why it's hard on Linux specifically. seccomp filters syscalls by (domain, type), never by the
destination path (the connect() sockaddr is behind a pointer the filter can't dereference). So the
static filter can only choose "all AF_UNIX or none" — it can't tell the ssh-agent socket from
docker.sock, since they're the same (AF_UNIX, SOCK_STREAM) class. And because the sandbox
bind-mounts the host filesystem read-only, every host socket path is visible inside, so a path-blind
allow would expose everything — which is exactly why the filter blocks AF_UNIX wholesale. macOS can
offer allowUnixSockets because Seatbelt rules are path-based; Linux seccomp has no path equivalent.

The options I could find:

| Mechanism | Path allowlist? | Privilege | Kernel | In-kernel? | Usable today? |
|---|---|---|---|---|---|
| Mount-masking — tmpfs the socket dirs, rebind the allowed one | ✗ — it's a denylist; can't express "allow only these" without enumerating every socket dir or inverting the fs model | unprivileged | any | ✓ | ✓ (but wrong contract) |
| Landlock (RESOLVE_UNIX) | ✓ | unprivileged | ABI 9 — merged to mainline, not in a released kernel yet (~7.1) | ✓ | ✗ — not in a released kernel |
| cgroup-eBPF (cgroup/connect_unix) | ✓ | privileged (CAP_BPF + CAP_NET_ADMIN + a managed cgroup) | ≥ 6.7 | ✓ | partial — needs BPF + cgroup control |
| seccomp-notify — a supervisor mediates each connect() | ✓ | unprivileged | ~5.9+ | ✗ — userspace mediator | ✓ |

Bottom line. Landlock's RESOLVE_UNIX is the clean endgame — unprivileged, in-kernel, by-path —
but it's only just merged to mainline and won't reach most users' kernels for years. Until then the two
genuinely-viable options are a privilege tradeoff: cgroup-eBPF (in-kernel, but needs privileged
setup and kernel ≥ 6.7) vs. a seccomp-notify broker (unprivileged and zero-setup, but it moves a small
security-relevant component into userspace). Of the two, seccomp-notify is the one I implemented and
tested end-to-end (against real Claude Code) — it's in the repo with its mechanism writeup and a
red-team record. I also included the mount prototype, mainly to show concretely why masking can't be
a true allowlist.

(I also opened a design issue on the sandbox repo — anthropic-experimental/sandbox-runtime#343)

Showing cached comments. Read the full discussion on GitHub ↗