[BUG] macOS sandbox blocks `bind()` on Unix domain sockets for child processes, breaking `dotnet build` parallelism

Resolved 💬 4 comments Opened Mar 26, 2026 by Bouke Closed May 25, 2026

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report (please file separate reports for different bugs)
  • [x] I am using the latest version of Claude Code

What's Wrong?

On macOS, the sandbox blocks bind() on Unix domain sockets for processes spawned via Process.Start() (child/grandchild processes). This breaks any tool that uses named pipes for inter-process communication, including dotnet build which uses MSBuild out-of-process worker nodes.

The sandbox settings allowAllUnixSockets, allowLocalBinding, enableWeakerNestedSandbox, and enableWeakerNetworkIsolation do not resolve this.

What Should Happen?

Steps to reproduce

  1. Enable the sandbox in ~/.claude/settings.json:

``json
{
"sandbox": {
"enabled": true,
"autoAllowBashIfSandboxed": true,
"network": {
"allowAllUnixSockets": true,
"allowLocalBinding": true
}
}
}
``

  1. Create a solution with at least 2 projects (a library and a dependency), so MSBuild spawns worker nodes.
  1. Run dotnet build via the Bash tool (without -maxcpucount:1).

Expected behavior

Build completes using parallel MSBuild nodes (takes ~1 second).

Actual behavior

Build hangs for exactly 5 minutes (MSBuild's default node connection timeout), then fails with 0 errors. MSBuild writes failure files to $TMPDIR/MSBuildTemp/ with this stack trace:

System.Net.Sockets.SocketException (13): Permission denied
   at System.Net.Sockets.Socket.DoBind(EndPoint endPointSnapshot, SocketAddress socketAddress)
   at System.Net.Sockets.Socket.Bind(EndPoint localEP)
   at System.IO.Pipes.NamedPipeServerStream.SharedServer..ctor(String path, ...)
   at Microsoft.Build.BackEnd.NodeEndpointOutOfProcBase.InternalConstruct(String pipeName)
   at Microsoft.Build.Execution.OutOfProcNode.Run(...)

MSBuild spawns worker node child processes. These child processes try to create a NamedPipeServerStream, which on macOS calls bind() on a Unix domain socket. The sandbox blocks this bind() call with EACCES (errno 13). The parent MSBuild process waits for the worker to connect (which never happens), hanging for the full 5-minute timeout.

Key diagnostic finding

A direct .NET process CAN create named pipes inside the sandbox:

// This WORKS when run directly via `dotnet run`
using var server = new NamedPipeServerStream("test", PipeDirection.InOut, 1,
    PipeTransmissionMode.Byte, PipeOptions.Asynchronous | PipeOptions.CurrentUserOnly, 0, 0);

But when that same process spawns a child via Process.Start(), the child process CANNOT create named pipes — the bind() call fails with Permission denied. This confirms the sandbox applies different restrictions to descendant processes than to the direct process.

A Python test also confirms direct socket.bind() on AF_UNIX works in the sandbox — the restriction is specific to child processes.

Suggested fix

The macOS sandbox profile should allow bind() on AF_UNIX sockets when allowAllUnixSockets: true is set, including for descendant processes — not just the direct child of the sandboxed shell. This is needed by any tool that uses named pipes for IPC between parent and child processes (MSBuild, Roslyn VBCSCompiler, and likely other build systems).

Settings that were tested (none fixed the issue)

| Setting | Effect |
|---|---|
| allowAllUnixSockets: true | No effect on child process bind() |
| allowLocalBinding: true | No effect on child process bind() |
| allowUnixSockets: ["/tmp/claude/", ...] | No effect |
| enableWeakerNestedSandbox: true | No effect |
| enableWeakerNetworkIsolation: true | No effect |
| ignoreViolations: {"network-bind": ["*"]} | Only suppresses logging, doesn't allow the operation |

Workaround

Use excludedCommands: ["dotnet build:*", "dotnet test:*"] to run dotnet commands outside the sandbox. This defeats the purpose of sandboxing.

Alternatively, force single-node builds with dotnet build -maxcpucount:1, which avoids spawning child processes but loses multi-project parallelism.

Additional Information

Environment

Claude Model

Opus

Is this a regression?

I don't know

Last Working Version

_No response_

Claude Code Version

2.1.84 (Claude Code)

Platform

Anthropic API

Operating System

macOS

Terminal/Shell

iTerm2

Related issues

Several existing issues describe related sandbox problems, but none address this specific child-process bind() restriction:

Most closely related

  • #28954enableWeakerNetworkIsolation not wired from settings to sandbox-runtime config (closed as duplicate of #26466). Same architectural pattern: a sandbox setting exists in the schema but is never translated into the actual macOS Seatbelt profile. Our issue likely has the same root cause — allowAllUnixSockets and allowLocalBinding are accepted in config but not reflected in the generated Seatbelt rules for descendant processes.
  • #16076excludedCommands and allowUnixSockets not working (closed, not planned — redirected to #10524, #14162, #10767). Same symptom: setting is accepted but has no effect.
  • #35686 — Feature request for wildcard/regex support in sandbox.network.allowUnixSockets. Suggests the socket allowlisting mechanism needs broader improvements.

Sandbox blocking IPC / system services for child processes

  • #34876 — Sandbox blocks macOS Security.framework trustd IPC, breaking all Go binaries (gh, terraform, tofu). Same pattern: Seatbelt profile too restrictive for child process IPC.
  • #37481excludedCommands does not bypass macOS sandbox for Metal/GPU (IOKit) access. Another case where the sandbox blocks IPC that child processes need.
  • #38211 — Sandbox silently prevents cmake/ninja builds without error on Linux. Same class of problem on a different platform — build tools that spawn child processes fail silently.
  • #36759 — Sandbox sets TMPDIR to non-existent directory, causing child processes to hang. Related child-process sandbox issue.
  • #37990 — Sandbox blocks URLSession / CFNetwork on macOS. Another Seatbelt restriction affecting system framework access.

Sandbox config propagation issues

  • #37782allowedDomains does not work for Node.js processes (DNS resolution blocked). Settings not propagating to child processes.

How this bug is different

This report differs from existing issues in three ways:

  1. Root cause identified: We've isolated the problem to bind() on AF_UNIX sockets being blocked specifically for child/grandchild processes, not for the direct process. Previous reports describe the symptom (hang) without this diagnosis.
  1. Proof that settings are ignored: We've exhaustively tested every relevant sandbox setting (allowAllUnixSockets, allowLocalBinding, allowUnixSockets, enableWeakerNestedSandbox, enableWeakerNetworkIsolation, ignoreViolations) and confirmed none resolve the issue — pointing to a gap in how settings are translated to the Seatbelt profile.
  1. Direct vs child process divergence demonstrated: A direct dotnet run process can create NamedPipeServerStream (which calls bind() on AF_UNIX) inside the sandbox, but a child process spawned by that same process cannot. This narrows the fix to the Seatbelt rules applied to descendant processes.

🤖 Generated with Claude Code

View original on GitHub ↗

This issue has 4 comments on GitHub. Read the full discussion on GitHub ↗