[BUG] /sandbox seccomp filter instructions don't work, paths not read from settings

Status Fixed / completed
Reported on v2.1.37
Maintainer reply None cached
Activity 8 comments · opened Feb 8, 2026 · closed Aug 19, 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?

/sandbox reports that seccomp filter is not installed, despite the files present in the system and configured in settings.json:

$jq . ~/.claude/settings.json
{
  "applyPath": "/usr/lib/claude-code-seccomp/apply-seccomp",
  "sandbox": {
    "seccomp": {
      "bpfPath": "/usr/lib/claude-code-seccomp/vendor/seccomp/x64/unix-block.bpf",
      "applyPath": "/usr/lib/claude-code-seccomp/vendor/seccomp/x64/apply-seccomp"
    }
  }
}
$ls /usr/lib/claude-code-seccomp/vendor/seccomp/x64/
 apply-seccomp   unix-block.bpf

What Should Happen?

seccomp filter dependency should show as installed

Error Messages/Logs

Sandbox:  Mode   Dependencies   Overrides   Config  (←/→ or tab to cycle)


 bubblewrap (bwrap): installed

 socat: installed

 seccomp filter: not installed (required to block unix domain sockets)
   · npm install -g @anthropic-ai/sandbox-runtime
   · or copy vendor/seccomp/* from sandbox-runtime and set
     sandbox.seccomp.bpfPath and applyPath in settings.json

Steps to Reproduce

  1. configure as above
  2. claude /sandbox and navigate right to dependencies

Claude Model

None

Is this a regression?

I don't know

Last Working Version

_No response_

Claude Code Version

2.1.37 (Claude Code)

Platform

Anthropic API

Operating System

Other Linux

Terminal/Shell

Other

Additional Information

_No response_

View original on GitHub ↗

7 Comments

mkurz · 5 months ago

Same here. Seems like the config gets ignored...

mkurz · 5 months ago

It seems sandboxing in general works - "only" socket sandboxing is affected -

 Sandbox:  Mode   Dependencies   Overrides   Config  (←/→ or tab to cycle)                                                       
                                                                                                                                 

 Cannot block unix domain sockets (see Dependencies tab) 

 ...

I put following stupid script into my project folder (calling it formatter.sh...):

#!/usr/bin/env bash

date >> /home/mkurz/foo

So this bash script writes to the foo file in my home folder, which is not part of my project folder obviously.

When I tell claude to run this script - with strict sandbox mode enabled - I get:

● Bash(bash /home/mkurz/myproject/formatter.sh)                                                                     
  ⎿  Error: Exit code 1                                                         
     /home/mkurz/myproject/formatter.sh: line 3: /home/mkurz/study: Read-only file system                           
                                                                                                                                 
     /home/mkurz/myproject/formatter.sh: line 3: /home/mkurz/study: Read-only file system                           
                                                                                                                                 
● The script can't run in strict sandbox mode — writing to /home/mkurz/study is blocked. Strict mode prevents bypassing sandbox  
  restrictions. You'd need to disable or relax sandbox mode to run this script.           

With "Allow unsandboxed fallback" I can write the fall after confirming permission:

● Bash(bash /home/mkurz/myproject/formatter.sh)
  ⎿  (No output)

● The script ran successfully. The sandbox was restricting writes to /home/mkurz/study, so I bypassed it to allow the script to
  append the date to that file.

So this shows at least filesystem sandboxing is working.

mkurz · 5 months ago

I did some more research:

  • To reproduce make sure that you do not have @anthropic-ai/sandbox-runtime installed via npm (run npm uninstall -g @anthropic-ai/sandbox-runtime)
  • To reproduce also make sure that NPM_CONFIG_PREFIX is not set when starting claude - or set it to some non-existing path like /does/not/exist (e.g. by running NPM_CONFIG_PREFIX=/does/not/exist claude.

Those both requirements are important for reproduction because claude will fallback to search for the files in the most common npm locations and also tries to figure out the root of the current node installation by running npm -g root and then trying to locate the files from there.

So make sure that you have sandbox enabled and the paths set to the files. (On arch linux for example there is the claude-code-seccomp AUR that installs just the two files to /usr/lib/claude-code-seccomp/:

{
  "sandbox": {
    "enabled": true,
    "seccomp": {
      "bpfPath": "/usr/lib/claude-code-seccomp/unix-block.bpf",
      "applyPath": "/usr/lib/claude-code-seccomp/apply-seccomp"
    }
  }
}

Confirm both files exist and are readable/executable.

Use the SRT_DEBUG=1 env varible to debug logs regarding SeccompFilter will be written and then inspect the debug log:

NPM_CONFIG_PREFIX=/does/not/exist SRT_DEBUG=1 claude
grep SeccompFilter ~/.claude/debug/latest

Output:*

[SeccompFilter] Detected architecture: arm64
[SeccompFilter] Pre-generated BPF filter not found in any expected location (arm64)
[SeccompFilter] Looking for apply-seccomp binary for architecture: arm64
[SeccompFilter] apply-seccomp binary not found in any expected location (arm64)

After looking at the pretty-formatted (but still obfuscated) claude source code from its npm package, I think that the problem has something to do with how the config and sandbox gets initialized when starting claude.

mkurz · 5 months ago

(updated my previous comment with more relevant information how to reproduce)

taylorsw04 · 5 months ago

We are also seeing this issue.

tim-semba · 5 months ago

Confirming this is still present on v2.1.87 (Linux/WSL2 x86_64).

mkurz · 5 months ago

Now that the Claude Code source code leaked and is all over the internet, it is possible to trace the exact code path involved here and identify the root cause precisely instead of guessing from behavior alone.

I traced this through both claude-code and the actual @anthropic-ai/sandbox-runtime source, and the root cause appears to be in Claude Code’s adapter layer.

The problem is not that the seccomp paths are invalid. The problem is that Claude Code was not forwarding sandbox.seccomp into the runtime config that sandbox-runtime actually uses.

What I found:

In sandbox-runtime, checkDependencies() does not accept seccomp config as an argument. It only accepts ripgrep config, and on Linux it reads seccomp paths from the runtime’s internal config:

  • sandbox-manager.ts:

checkDependencies(ripgrepConfig?: { command: string; args?: string[] })

  • Inside that function, Linux dependency checks call:

checkLinuxDependencies(config?.seccomp)

Then in checkLinuxDependencies(seccompConfig), the runtime resolves:

  • seccompConfig?.bpfPath
  • seccompConfig?.applyPath

to determine whether seccomp is available.

So for /sandbox to show seccomp as installed, Claude Code must first ensure that sandbox-runtime’s internal config includes:

seccomp: {
  bpfPath: "...",
  applyPath: "..."
}

The bug in Claude Code is that its adapter never did that.

Specifically:

  1. convertToSandboxRuntimeConfig() did not include settings.sandbox.seccomp, so the runtime never received the configured seccomp paths for actual sandbox execution either.
  1. SandboxManager.checkDependencies() in Claude Code called into BaseSandboxManager.checkDependencies(...) without first updating the runtime’s internal config from current settings, so the dependency UI had no way to see the configured seccomp paths.

There is also a staleness problem:

  1. Claude Code memoized its zero-argument checkDependencies() wrapper, so even after settings changed, the dependency tab could keep showing old results until process restart.

The fix is:

  • Add seccomp: settings.sandbox?.seccomp to the config returned by convertToSandboxRuntimeConfig()
  • Before calling BaseSandboxManager.checkDependencies(...), call BaseSandboxManager.updateConfig(convertToSandboxRuntimeConfig(currentSettings))
  • Remove the zero-arg memoization on Claude Code’s checkDependencies() wrapper so dependency status reflects current settings
  • Optionally make sandbox.seccomp explicit in Claude Code’s local settings schema instead of relying on passthrough behavior

In other words, the issue is a config handoff bug between Claude Code and sandbox-runtime, not a problem with the seccomp files themselves.

This also means the bug affects more than just the /sandbox dependency tab: custom sandbox.seccomp.bpfPath / applyPath were also being ignored by actual sandbox setup, because the runtime config was missing seccomp entirely.

Patch diff:

diff --git a/entrypoints/sandboxTypes.ts b/entrypoints/sandboxTypes.ts
index b38a156..6fd715c 100644
--- a/entrypoints/sandboxTypes.ts
+++ b/entrypoints/sandboxTypes.ts
@@ -85,6 +85,26 @@ export const SandboxFilesystemConfigSchema = lazySchema(() =>
     .optional(),
 )
 
+/**
+ * Linux seccomp helper configuration schema.
+ */
+export const SandboxSeccompConfigSchema = lazySchema(() =>
+  z
+    .object({
+      bpfPath: z
+        .string()
+        .optional()
+        .describe('Path to the seccomp BPF file used to block Unix sockets'),
+      applyPath: z
+        .string()
+        .optional()
+        .describe(
+          'Path to the apply-seccomp helper binary that installs the filter',
+        ),
+    })
+    .optional(),
+)
+
 /**
  * Sandbox settings schema.
  */
@@ -120,6 +140,7 @@ export const SandboxSettingsSchema = lazySchema(() =>
         ),
       network: SandboxNetworkConfigSchema(),
       filesystem: SandboxFilesystemConfigSchema(),
+      seccomp: SandboxSeccompConfigSchema(),
       ignoreViolations: z.record(z.string(), z.array(z.string())).optional(),
       enableWeakerNestedSandbox: z.boolean().optional(),
       enableWeakerNetworkIsolation: z
@@ -151,6 +172,9 @@ export type SandboxNetworkConfig = NonNullable<
 export type SandboxFilesystemConfig = NonNullable<
   z.infer<ReturnType<typeof SandboxFilesystemConfigSchema>>
 >
+export type SandboxSeccompConfig = NonNullable<
+  z.infer<ReturnType<typeof SandboxSeccompConfigSchema>>
+>
 export type SandboxIgnoreViolations = NonNullable<
   SandboxSettings['ignoreViolations']
 >
diff --git a/utils/sandbox/sandbox-adapter.ts b/utils/sandbox/sandbox-adapter.ts
index 170ecac..1ac4acf 100644
--- a/utils/sandbox/sandbox-adapter.ts
+++ b/utils/sandbox/sandbox-adapter.ts
@@ -376,6 +376,7 @@ export function convertToSandboxRuntimeConfig(
     enableWeakerNestedSandbox: settings.sandbox?.enableWeakerNestedSandbox,
     enableWeakerNetworkIsolation:
       settings.sandbox?.enableWeakerNetworkIsolation,
+    seccomp: settings.sandbox?.seccomp,
     ripgrep: ripgrepConfig,
   }
 }
@@ -445,16 +446,19 @@ async function detectWorktreeMainRepoPath(cwd: string): Promise<string | null> {
 }
 
 /**
- * Check if dependencies are available (memoized)
+ * Check if dependencies are available
  * Returns { errors, warnings } - errors mean sandbox cannot run
  */
-const checkDependencies = memoize((): SandboxDependencyCheck => {
+function checkDependencies(): SandboxDependencyCheck {
+  const settings = getSettings_DEPRECATED()
+  const runtimeConfig = convertToSandboxRuntimeConfig(settings)
+  BaseSandboxManager.updateConfig(runtimeConfig)
   const { rgPath, rgArgs } = ripgrepCommand()
   return BaseSandboxManager.checkDependencies({
     command: rgPath,
     args: rgArgs,
   })
-})
+}
 
 function getSandboxEnabledSetting(): boolean {
   try {
@@ -813,7 +817,6 @@ async function reset(): Promise<void> {
   bareGitRepoScrubPaths.length = 0
 
   // Clear memoized caches
-  checkDependencies.cache.clear?.()
   isSupportedPlatform.cache.clear?.()
   initializationPromise = undefined
 

Showing cached comments. Read the full discussion on GitHub ↗