[BUG] apply-seccomp fails on Linux - cannot write /proc/self/setgroups
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?
All Bash commands fail in Claude Code 2.1.92 on Ubuntu 25.10 with:
apply-seccomp: write /proc/self/setgroups (nested userns is capability-restricted; caller must provide CAP_SYS_ADMIN): Permission denied
The new apply-seccomp binary (shipped in 2.1.92 per changelog: "Linux sandbox now ships the apply-seccomp helper") writes to /proc/self/setgroups before mapping UID. Tested on kernel 6.17.0-14 and 6.17.0-20, both fail.
What Should Happen?
Bash commands should execute successfully inside the sandbox. The apply-seccomp helper should work on Linux kernel (Ubuntu 25.10). Version 2.1.91 worked fine - no sandbox errors.
Error Messages/Logs
apply-seccomp: write /proc/self/setgroups (nested userns is capability-restricted; caller must provide CAP_SYS_ADMIN): Permission denied
Steps to Reproduce
# This pattern is what apply-seccomp does internally
unshare -U bash -c "echo deny > /proc/self/setgroups"
# → Permission denied
# With UID mapping first - works:
unshare -Ur echo test
# → test
Claude Model
Opus
Is this a regression?
Yes, this worked in a previous version
Last Working Version
2.1.91
Claude Code Version
2.1.92
Platform
Anthropic API
Operating System
Ubuntu/Debian Linux
Terminal/Shell
Other
Additional Information
Downgrading fixes the issue
ln -sf /home/crazyfrogspb/.local/share/claude/versions/2.1.91 /home/crazyfrogspb/.local/bin/claude
28 Comments
I'm having the same issue.
To get functional again, I needed to reinstall an older version: $ claude install 2.1.91
Does Anthropic even test the sandbox?
The issue is that the built-in
apply-seccompfile lacks execution permissions.node_modules/@anthropic-ai/claude-code/vendor/seccomp/{your-arch}/apply-seccompFor example, on macOS homebrew:
sudo chmod +x /opt/homebrew/lib/node_modules/@anthropic-ai/claude-code/vendor/seccomp/*/apply-seccompFor Linux:
sudo chmod +x /usr/local/lib/node_modules/@anthropic-ai/claude-code/vendor/seccomp/*/apply-seccomp(or under
/usr/bin/...)Previously,
ripgrepmade this exact same mistake, yet here we are seeing the same error repeated.With the NPM install, it appears to be true that apply-seccomp isn't set to executable, that isn't the cause of the CAP_SYS_ADMIN error we're focused on here. Also the native install method (rather than npm) doesn't appear to have the permission issue. The apply-seccomp call is executing, but hitting an error.
I'm guessing this is because Ubuntu has extra restrictions on unprivileged user namespaces: https://discourse.ubuntu.com/t/ubuntu-24-04-lts-noble-numbat-release-notes/39890#p-99950-unprivileged-user-namespace-restrictions-15
However, the command in that thread to disable that restriction (
echo 0 | sudo tee /proc/sys/kernel/apparmor_restrict_unprivileged_userns) did _not_ work for me: I get the same error after running it.Disabling AppArmor entirely via kernel cmdline did get the sandbox to start, but that severely reduces Ubuntu's security, so I don't want to do that.
(Also, I believe the change that introduced the nested user namespaces in the sandbox was https://github.com/anthropic-experimental/sandbox-runtime/commit/7ee4ac602d18d7261c6d4db77014b2bc2617cb60)
Anthropic has now released a broken version to the "stable" channel, so I had to turn off auto-update to keep the last working version 2.1.91. I worked with claude extensively to try and find a workaround that didn't involve disabling apparmor or disabling the claude sandbox, and ultimately failed to find anything that worked.
Can you confirm it works for you if you uninstall
socat? See #49018The only real workaround that I found:
1) Install via npm: npm install -g @anthropic-ai/claude-code@latest
2) Fix executable bit: chmod +x <npm-prefix>/lib/node_modules/@anthropic-ai/claude-code/vendor/seccomp/x64/apply-seccomp
3) Comment out capability deny in /etc/apparmor.d/bwrap-userns-restrict:
# audit deny capability,4) Reload: sudo apparmor_parser -r /etc/apparmor.d/bwrap-userns-restrict
5) Rename binary: mv ~/.local/bin/claude ~/.local/bin/claude-native-backup
Warning - this allows capabilities for all bwrap-sandboxed processes (Flatpak, etc.) within their user namespace
Still waiting for the real fix
The issue only seems to go away if I uninstall socat, which is equivalent to disabling the sandbox because it's a missing dependency. The /doctor command indicates sandbox disabled.
Confirmed on Ubuntu 24.04 LTS, kernel 6.17.0-20-generic (npm install)
Why 2.1.91 "works" on my system: socat is not installed. Without socat, 2.1.91 skips the sandbox entirely — Bash runs unsandboxed (Seccomp: 0, no user namespace). This is not a fix, just the sandbox being absent.
Why 2.1.92+ breaks even without socat: The new
apply-seccomphelper is called regardless of socat availability. It attempts to write/proc/self/setgroupsinside a user namespace, which fails withCAP_SYS_ADMINdenied becauseapparmor_restrict_unprivileged_userns=1(Ubuntu 24.04 default).So the regression is: 2.1.91 had a dependency (socat) that gracefully degraded to no sandbox. 2.1.92+ ships its own binary that fails fatally with no fallback on AppArmor-restricted systems.
Staying on 2.1.91 (unsandboxed) with auto-update disabled until this is fixed.
I seem to be hitting the same issue on 2.1.116. I set
allowAllUnixSockets: truefor now, which has solved it.Please make Claude with sandbox usable again. Still stuck to 2.1.87 because of this and #43713.
ChatGPT gave me this working workaround for Claude 2.1.121 on Ubuntu 25.10, I think it weakens sandbox a bit but not sure exactly by how much:
~/.claude/settings.json
Also getting hit by this one with: Claude Code 2.1.126, Ubuntu 25.10, kernel 6.17.0-22-generic
Check if you have other apparmor profiles interfering with the bwrap profile.
For example,
unpriv_bwrapis a profile declared by Lutris:Its
audit deny capabilitycannot be overridden bylocal/unpriv_bwrap(apparmordenyrules always take precedence overallowrules), but at least you can monkeypatch the file (and file an issue against lutris):The upstream version is available as
/usr/share/apparmor/extra-profiles/bwrap-userns-restrict.Not sure if that's desirable, though. https://gitlab.com/apparmor/apparmor/-/work_items/382 applies.
It helps me on Ubuntu 26.04, but my profile is called
/etc/apparmor.d/bwrap-userns-restrictHey @egorkel-altexsoft, something seems to have gone wrong with your message.
Could you please check the formatting of your comment?
You can edit it from the "..." menu, and fix the message.
Currently, it is unintelligible.
This worked for me, and threaded the needle of turning off protections globally to get sandboxing to work, which of course wouldnt make sense.
Thanks!
Still reproduces on Ubuntu 26.04 / kernel 7.0.0-15-generic / native install 2.1.185
(~90 releases and 4 months after this was filed, on a newer kernel than #56345's 6.17).
Error (identical to #56345):
apply-seccomp: write /proc/self/setgroups (nested userns is capability-restricted;
caller must provide CAP_SYS_ADMIN): Permission denied
Key data point:
kernel.apparmor_restrict_unprivileged_userns=0does NOT fix it.Verified
=0via /proc, sandbox still fails identically. So the userns create-gatesysctl isn't the lever — the capability denial comes from the
unpriv_bwrapchildprofile in
/etc/apparmor.d/bwrap-userns-restrict(audit deny capability,), whichstrips caps from bwrap's sandboxed children, including the bundled
apply-seccomphelper. Matches the
profile="unpriv_bwrap" comm="apply-seccomp" capname="sys_admin"audit line reported earlier in this thread.
The OS is otherwise healthy — every primitive the sandbox needs works outside the
bundled helper:
unshare -U true # OK
unshare -rU true # OK (map-root)
unshare -rUm true # OK (+mount ns)
unshare -rU bash -c 'unshare -rU true' # OK (double-nested userns)
unshare -rUn sh -c 'ip link set lo up' # OK (netns + loopback up)
bwrap --unshare-user --unshare-net --ro-bind / / true # OK
bwrap --unshare-user --unshare-pid --proc /proc --dev /dev --ro-bind / / true # OK
So this is distinct from #55585/#14719 (the
bwrap: loopback: Failed RTM_NEWADDRnetns class) — loopback-in-userns works here.
/usr/bin/bwrapsucceeds because it hasthe permissive
profile bwrapattachment; only the vendoredapply-seccomphelper,running as a cap-stripped bwrap child, fails.
For other Linux users landing here: the macOS
allowAllUnixSocketsworkaround does notexist on Linux (#44180), so it's not a fix. What restores function is disabling the
sandbox (
sandbox.enabled: false) or relaxingunpriv_bwrapsystem-wide (broad — itre-grants capabilities to every bwrap sandbox, e.g. Flatpak).
Impact: this has forced us to set
sandbox.enabled: falseacross our multi-userUbuntu 26.04 dev fleet — i.e. an OS-level security feature turned off in production
because of this regression, with no per-setting workaround on Linux. A fix (or a
documented, narrowly-scoped Linux escape hatch) would be much appreciated.
Environment:
bwrap-userns-restrictprofile loadedHave you reported the issue to Ubuntu? This is a bug in their apparmor policy, not the sandbox runtime.
For people still having issues on Ubuntu - try re-doing the instructions in the sandbox configuration to allow bubblewrap to create user namespaces:
then
sudo systemctl reload apparmorthen restart Claude (and/or your machine). This worked for me.
For anyone interested, https://nono.sh intentionally runs with landlock, which means no requirement for namespaces / CAP_SYS_ADMIN. We have many linux users running fedora, ubuntu, arch, debian etc..
Just download the binary, and run
nono run --profile nolabs-ai/claude -- claude --dangerously-skip-permissionsand your sandboxed.Root cause, with an isolation matrix. Short version: this is not about capabilities or nested-userns policy — it is
bwrapitself settingsetgroups=deny, which the kernel then makes permanent and unwritable for every descendant namespace.Environment: Claude Code 2.1.222 · Ubuntu, kernel 7.0.0-28-generic · bubblewrap 0.11.1 ·
@anthropic-ai/sandbox-runtime0.0.70 ·apparmor_restrict_unprivileged_userns=0, AppArmorunconfined,unprivileged_userns_clone=1, valid/etc/subuid+/etc/subgid, not in a container, initial userns (identityuid_map).Isolation matrix
Running the vendored
apply-seccompbinary directly, varying only the surroundingbwrapinvocation:| | invocation | result |
|---|---|---|
| C | no
bwrapat all | ✅ succeeds || A |
bwrap --unshare-user --cap-drop ALL --proc /proc(current default) | ❌ EPERM || B |
bwrap --unshare-user --bind /proc /proc(enableWeakerNestedSandbox: true) | ❌ EPERM || D |
bwrap --unshare-user --cap-add CAP_SYS_ADMIN| ❌ EPERM |The helper works fine on its own. It fails inside any
bwrapuser namespace, and--cap-add CAP_SYS_ADMINdoes not help — so the error message's advice ("caller must provide CAP_SYS_ADMIN") does not actually resolve it, and capabilities are not the blocker.The mechanism
Because
bwrapis not setuid on Debian/Ubuntu, it creates its user namespace unprivileged, and the kernel requires it to writedenyto/proc/self/setgroupsto do so. Peruser_namespaces(7), oncesetgroupsisdenyin an ancestor namespace it is permanentlydenyin all descendants and the file becomes unwritable:apply-seccomp.cfallback path (b) creates a nested userns and unconditionally writesdenytosetgroups. Insidebwrapthat write is both redundant (alreadydeny, inherited) and impossible (kernel forbids it) — and it is treated as fatal.This also explains why the bug is Linux-distro-dependent rather than kernel-version-dependent: on systems shipping
bwrapsetuid-root the namespace is created privileged,setgroupsstaysallow, and the write succeeds.Suggested fix
In
apply-seccomp.c, before thesetgroupswrite, read/proc/self/setgroups; if it already readsdeny, skip the write instead of failing. Equivalently, tolerateEPERMthere when the current value is alreadydeny— the desired end state is satisfied either way. The subsequentuid_map/gid_mapwrites are unaffected, since a single-entry identity mapping of the caller's own uid/gid does not requiresetgroupsto be writable.Failing that, the diagnostic should name the real unmet condition —
setgroupsisdenyin an ancestor namespace — rather than pointing atCAP_SYS_ADMIN, which demonstrably does not fix it (row D).Workaround
"allowAllUnixSockets": trueskips the seccomp filter entirely, so the sandbox arms and the filesystem/network restrictions still apply — corroborating #81799, which reports the same bug on this same kernel.enableWeakerNestedSandbox: truemakes no difference (row B).Created better sandboxing solution for linux users: https://jailbee.gisgro.io/
Reproduced on the latest release (2.1.233). In an environment where user namespaces can be created but don't grant capabilities (the default AppArmor policy on newer Ubuntu, including 25.10, and many containers), every sandboxed Bash command fails during sandbox setup with an
apply-seccomp: ... Permission deniederror — on some kernels the failing write issetgroups, on othersuid_map, but it's the same underlying failure.This is a regression introduced in 2.1.92, when the Linux sandbox started shipping the seccomp helper (see the 2.1.92 changelog entry). The helper needs to set up a capability-bearing nested user namespace, which these environments block. 2.1.91 didn't ship the helper, so it didn't hit this.
Workarounds until a fix lands:
sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0(weakens system hardening — see the sandboxing docs troubleshooting section)enableWeakerNestedSandboxsandbox setting may helpKeeping this open as a reproduced regression.
🤖 Generated with Claude Code
Fresh measurements on 2.1.234 (Ubuntu 26.04 LTS, kernel 7.0.0-28-generic, KVM VM, bubblewrap 0.11.1 non-setuid, stock AppArmor profile set —
bwrap-userns-restrictandunprivileged_userns, no custombwrapprofile —apparmor_restrict_unprivileged_userns=1, native install), following up on the confirmation above:Still reproduces on 2.1.234, in both strict and default mode. Headless probes with
--settings '{"sandbox":{"enabled":true,...}}', re-run with a scrubbed environment from a fresh $HOME directory:| settings | result |
|---|---|
|
{"enabled":true,"allowUnsandboxedCommands":false}| ❌ every command:apply-seccomp: write /proc/self/setgroups (...): Permission denied||
{"enabled":true}(defaults) | ❌ same error on every command's first attempt; recovery relies on a model retry withdangerouslyDisableSandbox, which then runs unsandboxed ||
{"enabled":true,"allowUnsandboxedCommands":false,"network":{"allowAllUnixSockets":true}}| ✅ commands run; probe showssetgroups=deny, a non-initial userns, writes outside the workspace denied, writes in cwd allowed |Two notes on the environment:
@anthropic-ai/sandbox-runtimeis not installed on this machine. The sandboxing docs call the seccomp filter optional ("install it with npm ... if it is missing"), but the native binary applies the bundled helper even with the package absent — so skipping the npm package is not an escape hatch, and the docs' optionality doesn't hold for native installs.unshare -Urwent from working to failing at theuid_mapwrite — consistent with "on some kernels the failing write is uid_map". The stockunprivileged_usernsprofile (audit deny capability, transitioned to from unconfined) is what strips the capabilities.So
network.allowAllUnixSockets: truerestores a fully armed sandbox — filesystem isolation enforced, only the Unix-socket filter skipped — corroborating @luispabon and #81799 on 2.1.234. A far better interim position thansandbox.enabled: false, which is where this bug had pushed our fleet.On workaround 1:
kernel.apparmor_restrict_unprivileged_userns=0did not resolve this when I measured it in June on 7.0.0-15, and #81799 reproduces the identical failure on 7.0.0-28 with both apparmor sysctls=0and AppArmor unconfined end to end — consistent with @luispabon's matrix: the blocker is bwrap's inheritedsetgroups=deny, which no sysctl lifts once the ancestor namespace carries it. Their suggested fix — tolerate the redundantdenywrite whensetgroupsalready readsdeny— still looks like the cheapest correct one, and would makeallowAllUnixSocketsunnecessary as a workaround.(Method note: probes ran via headless
claude -pon a fleet machine whose org-managed hooks are unrelated to sandboxing; #81799 shows the same repro in a clean-roomCLAUDE_CONFIG_DIRwith no hooks.)<p dir="ltr">We can reproduce this on Ubuntu 26.04, and can add data that may be useful: the same failure across <strong>three separate CLI versions over nine days on the same machine and configuration</strong>, which suggests the 2.1.91→2.1.92 regression has not self-resolved in later releases.</p>
<div dir="ltr">
Date | apt CLI version | Result
-- | -- | --
2026-08-16 | 2.1.224 | same failure
2026-08-17 | 2.1.226 | same failure
2026-08-24 | 2.1.231 | same failure
</div>
<p dir="ltr">Exact error, unchanged across all three:</p>
<div role="group" aria-label="Code" tabindex="0"><div><div></div></div><div><pre style="color: rgb(234, 236, 240); background: transparent; font-family: var(--font-mono);"><code style="color: rgb(234, 236, 240); background: transparent; font-family: var(--font-mono); white-space: pre-wrap;">apply-seccomp: write /proc/self/setgroups (nested userns is
capability-restricted; caller must provide CAP_SYS_ADMIN): Permission denied</code></pre></div></div>
<p dir="ltr"><strong>Environment:</strong> Ubuntu 26.04, kernel <code>7.0.0-30-generic</code>, apparmor 5.0.2-0ubuntu1~26.04.1, <code>kernel.apparmor_restrict_unprivileged_userns = 1</code> (set deliberately by us, in <code>/etc/sysctl.d/</code>), distribution-supplied <code>/etc/apparmor.d/bwrap-userns-restrict</code> unmodified (hash-verified unchanged across the whole period). <code>bubblewrap</code> installed; flatpak is not installed.</p>
<p dir="ltr">On our end we independently ruled out an AppArmor-side cause: a single-level bwrap invocation (<code>--unshare-user --cap-drop ALL</code>) runs fine on this machine; only the nested case fails, consistent with the write-before-UID-mapping order already identified in this thread. We also checked whether the profile's own local-override hooks (<code>include if exists <local/...></code>) could work around it — they can't, because the blocking rule is an <code>audit deny capability</code> and in AppArmor <code>deny</code> always wins over <code>allow</code> regardless of ordering or override.</p>
<p dir="ltr">Not asking for a workaround — just flagging that this is a stable, multi-version regression rather than a one-off, in case that's useful for prioritization.</p>
<p dir="ltr"><strong>Attachment:</strong> raw output, verbatim except two unrelated warning lines removed and the home directory path replaced with <code>/home/<user></code>.</p>
<div role="group" aria-label="Code" tabindex="0"><div><div></div></div><div><pre style="color: rgb(234, 236, 240); background: transparent; font-family: var(--font-mono);"><code style="color: rgb(234, 236, 240); background: transparent; font-family: var(--font-mono); white-space: pre-wrap;">2.1.231 (Claude Code)
apply-seccomp: write /proc/self/setgroups (nested userns is capability-restricted; caller must provide CAP_SYS_ADMIN): Permission denied</code></pre></div></div>