Linux terminal sandbox always fails preflight on RHEL 9 / Rocky 9: bubblewrap cannot bind-mount onto the symlinked CA bundle

Where does the bug appear (feature/product)?

Cursor IDE

Describe the Bug

On RHEL-family Linux (RHEL 9 / Rocky Linux 9), every agent terminal command fails at sandbox
preflight, so the agent cannot run any shell command at all. Neither sandbox backend can initialise:

  • Landlock is unavailable on the el9 kernel (5.14). This is expected and documented.
  • Bubblewrap fails because cursorsandbox bind-mounts onto hardcoded CA-bundle paths that
    RHEL-family distros ship as symlinks, and bubblewrap cannot bind-mount onto a symlink
    destination.

The second point is the actual bug, and it makes the sandbox unusable on every RHEL, Rocky,
AlmaLinux and Fedora host, because the symlinked CA bundle comes from the standard ca-certificates
package.

The symptom is badly misleading. Commands return no exit status at all, so the terminal appears to
hang rather than reporting a configuration error. It took a long debugging session to work out that
this was a sandbox preflight failure and not a hung shell.

Full error text:

Error: Failed to resolve Linux sandbox backend: Unsupported sandbox configuration: Linux auto
backend selection failed. Landlock error: Unsupported sandbox configuration: Failed to apply
Landlock: Step 5/7 (landlock) failed: Failed to apply Landlock: Landlock V3 filesystem
restrictions not supported. Error: fully incompatible access-rights:
BitFlags<AccessFs>(0b111111111110010, WriteFile | RemoveDir | RemoveFile | MakeChar | MakeDir |
MakeReg | MakeSock | MakeFifo | MakeBlock | MakeSym | Refer | Truncate). Ensure Landlock LSM is
enabled (CONFIG_SECURITY_LANDLOCK=y) on a kernel with V3 support.. Bubblewrap error:
Unsupported sandbox configuration: Unsupported sandbox configuration: Bubblewrap preflight
failed with exit code Some(1): bwrap: Can't create file at /etc/ssl/cert.pem: No such file or
directory

ROOT CAUSE

cursorsandbox contains a hardcoded list of CA-bundle paths (extracted with strings). On RHEL-family
systems the ca-certificates package ships most of them as symlinks into /etc/pki/ca-trust/extracted.
Only one is a regular file. Checked on this host:

/etc/pki/tls/certs/ca-bundle.crt    SYMLINK -> /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem   bind FAILS
/etc/ssl/cert.pem                   SYMLINK -> /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem   bind FAILS
/etc/ssl/certs/ca-certificates.crt  absent
/etc/ssl/ca-bundle.pem              absent
/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem   REGULAR FILE                                   bind OK

Bubblewrap refuses to bind-mount onto a destination that is a symlink, even when the symlink’s
target exists inside the sandbox. Because update-ca-trust recreates these symlinks, de-symlinking
them on the host is not a viable workaround.

Steps to Reproduce

Any RHEL 9 / Rocky 9 / AlmaLinux 9 host reproduces this, with or without Cursor. The failing
bind-mount can be reproduced with bubblewrap directly.

  1. Confirm the distro ships the CA bundle as a symlink:

    ls -l /etc/ssl/cert.pem /etc/pki/tls/certs/ca-bundle.crt

    Both are symlinks to /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem.

  2. Reproduce the exact preflight failure. This is the same bind Cursor performs:

    bwrap --ro-bind / / --ro-bind /etc/hostname /etc/ssl/cert.pem – /usr/bin/true; echo $?

    Result:

    bwrap: Can’t create file at /etc/ssl/cert.pem: No such file or directory
    1

  3. Show that the same bind succeeds against the real file the symlink points to, which is what
    canonicalizing the destination would produce:

    bwrap --ro-bind / / --ro-bind /etc/hostname
    /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem – /usr/bin/true; echo $?

    Result: 0

  4. Optional, to prove the symlink is the only variable, in a directory unrelated to certificates:

    mkdir -p /tmp/sslcheck/real /tmp/sslcheck/lnk
    echo bundle > /tmp/sslcheck/real/cert.pem
    ln -s /tmp/sslcheck/real/cert.pem /tmp/sslcheck/lnk/cert.pem

    regular-file destination → succeeds, exit 0

    bwrap --ro-bind / / --ro-bind /etc/hostname /tmp/sslcheck/real/cert.pem – /usr/bin/true; echo $?

    symlink to that same file as destination → fails, exit 1, identical error

    bwrap --ro-bind / / --ro-bind /etc/hostname /tmp/sslcheck/lnk/cert.pem – /usr/bin/true; echo $?

    Same filename, same directory depth, same target contents. Only the symlink differs.

  5. In Cursor on such a host, run any agent terminal command. It returns no exit status, and the
    error above appears.

Expected Behavior

Two separate expectations are not met.

  1. The sandbox should initialise. Binding a read-only CA bundle should succeed on a stock
    RHEL-family host. Canonicalizing the destination path before binding would achieve this, since
    the symlink target is a normal readable file that binds without error.

  2. Failing that, Cursor should fall back to approval prompts rather than failing every command. The
    docs page “Agent Security / Run Modes” (Linux sandboxing section) states:

    “If your kernel does not meet these requirements, Cursor falls back to asking for approval
    before running commands.”

    Docs URL: Run Modes | Cursor Docs

    The el9 kernel does not meet the documented Landlock v3 / kernel 6.2+ requirement, so the
    documented behaviour here is a fallback to approval prompts. What actually happens is a hard
    preflight failure on every command, with no fallback and no prompt.

Additionally, the failure should be visible. Commands currently return no exit status, which makes a
configuration problem look like a hung terminal. Reporting “sandbox unavailable: ” would
have made this self-diagnosing.

Operating System

Linux

Version Information

Cursor version: 3.12.10 (stable)
Commit: 24a12dbd9cabf48956ce5bb3dbd234e41385b3d0
VSCode version: 1.128.0
Build date: 2026-07-16

OS: RHEL 9 family (Rocky Linux 9), x86_64
Kernel: 5.14.0 (el9 series), which predates the documented 6.2 Landlock requirement
Setup: Remote-SSH. Workspace and $HOME on NFS, caches symlinked to local disk.
Active LSMs: lockdown, capability, yama, bpf. Landlock is not present at all.
Unprivileged user namespaces: available. Bubblewrap itself runs fine.
cursor-sandbox-apparmor RPM: not installed, and not applicable (see Additional Information).

For AI issues: which model did you use?

n/a

For AI issues: add Request ID with privacy disabled

n/a

Additional Information

NOT A DUPLICATE OF THE EXISTING LINUX SANDBOX THREADS

Existing reports share the symptom (“preflight fails”) but have a different root cause and a
different fix. Those are AppArmor profile gaps on Debian/Ubuntu, where unshare(CLONE_NEWUSER)
returns EPERM/EACCES and preflight exits 101, fixed by uncommenting “userns,” and adding “network,”
to /etc/apparmor.d/cursor-sandbox. Search the forum for these titles (URLs omitted to stay under
the new-user link limit):

  • “Shell Sandbox preflight fails (Exit 101)” (Debian 13; also publishes the policy JSON quoted
    below)
  • “Agent CLI: Linux sandbox preflight fails (unshare EPERM)”
  • “AppArmor cursor-sandbox profile incomplete on Linux”
  • “Terminal sandbox could not start” (NoNewPrivs from Electron’s zygote)

This report is a distinct failure mode. Here the user namespace is created successfully, since
unprivileged userns is available and bubblewrap runs fine. Preflight fails later, at the bind-mount
stage, on a path that is a symlink. None of the AppArmor fixes apply, and this host has no AppArmor
in the active LSM list at all. Fixing the AppArmor profiles would not fix this.

ALREADY RULED OUT

  • Not a bubblewrap version issue. Both the distro build and a much newer one fail identically:

    /usr/bin/bwrap, root-owned      bubblewrap 0.6.3    FAILS
    conda-provided bwrap, user      bubblewrap 0.11.2   FAILS
    
  • Not a PATH shadowing issue. cursorsandbox requires a root-owned bwrap on PATH, so a user-owned
    build is rejected and /usr/bin/bwrap is used regardless of PATH order.

  • Not a user-namespace permission issue. Unprivileged userns is available and bubblewrap runs
    fine. The documented cursor-sandbox-apparmor RPM addresses userns permission errors and does
    not apply here.

  • Not stale state. Reproduced across window reloads and full server restarts.

CONFIRMATION OF WHAT GETS BIND-MOUNTED

A user in the Exit-101 thread published the policy their build passed to cursorsandbox, which
confirms the paths involved:

{"type":"workspace_readwrite","cwd":"/home/alex","additionalReadwritePaths":[],
 "additionalReadonlyPaths":["/etc/ssl/cert.pem","/private/etc/ssl/cert.pem",
   "/etc/ssl/certs/ca-certificates.crt","/etc/ssl/ca-bundle.pem",
   "/etc/pki/tls/certs/ca-bundle.crt",
   "/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem","/home/alex/.ssh"],
 "networkAccess":false,"disableTmpWrite":false}

Every CA path is an additionalReadonlyPath, and $HOME/.ssh is included, which accounts for both
failure modes below. Note the CLI surface has since changed: that build accepted
–sandbox-policy ‘’ inline, while current builds take --policy with the object nested
under a “sandbox” key. A version-appropriate policy file is therefore needed to drive the helper
directly. The bubblewrap-level reproduction in Steps to Reproduce is version-independent.

TWO RELATED BIND-MOUNT FAILURES, SAME ROOT CAUSE

While diagnosing, preflight moved through several paths as each was fixed. All are the same class of
bug, which is why a general fix is worth more than special-casing the CA bundle.

  1. Symlinked directories under $HOME. With $HOME on NFS and cache/config dirs symlinked to local
    disk, which is a very common corporate remote-dev arrangement, preflight failed first on
    $HOME/.vscode and then on $HOME/.cursor:

    bwrap: Can’t bind mount /oldroot//.vscode on /newroot//.vscode:
    Unable to mount source on destination: No such file or directory

    Note the policy resolves the source through the symlink but keeps the literal $HOME path as the
    destination, which is precisely the case bubblewrap rejects. Working around this meant converting
    those directories into real directories on NFS, which is undesirable and impossible for large
    caches.

  2. Dangling symlinks as bind sources. $HOME/.ssh is shared across hosts via NFS while /tmp is
    per-host, so per-host agent-socket symlinks such as $HOME/.ssh/ssh_auth_sock. legitimately
    dangle on every other host. Preflight aborted on the first one it encountered:

    bwrap: Can’t find source path /.ssh/ssh_auth_sock.: No such file or directory

    A single unresolvable socket belonging to an unrelated host makes the entire sandbox unusable.

PRIOR ART: THE SAME BUG AND ITS ACCEPTED FIX ELSEWHERE

systemd/mkosi hit this exact problem, a sandbox binding CA bundles that are symlink chains on
RHEL-family hosts, and resolved it the way proposed here. Search GitHub systemd/mkosi for:

  • issue “certificates not mounted if symlinked in host” (#3774)
  • issue “finalize_certificate_mounts fails when the CA bundle is a symlink chain” (#4277)
  • commit df43e40, which added --bind-nofollow / --ro-bind-nofollow to mkosi-sandbox because
    “bind mounting a file whose source does not exist anymore fails with ENOENT”

Their conclusion matches this report: dereference host symlinks at bind time, or bind the parent
directory instead of the symlinked file. systemd itself refuses non-canonical mount points for the
same underlying reason (“Mount path is not canonical (contains a symlink)”), so canonicalizing
before mounting is the established convention rather than a workaround.

Prior-art URL (one of the two allowed links): finalize_certificate_mounts fails when /etc/ssl/certs/ca-bundle.crt is a symlink chain (re-file of #3774 with Docker reproducer) · Issue #4277 · systemd/mkosi · GitHub

PROPOSED FIX

  1. Canonicalize bind destinations (realpath) before invoking bubblewrap, so a symlinked destination
    becomes a bind onto its real target. This resolves the CA-bundle failure and the symlinked-$HOME
    failures in one change.
  2. Deduplicate after canonicalization. On RHEL-family systems several of the hardcoded CA paths
    canonicalize to the same file, so the list collapses to a single bind rather than three
    conflicting ones.
  3. Skip or tolerate unresolvable sources, using --ro-bind-try / --bind-try or filtering paths that
    do not resolve, so one dangling symlink cannot abort the whole sandbox.
  4. Honour the documented fallback. When no backend can initialise, fall back to approval prompts as
    the documentation describes, instead of failing every command.
  5. Surface the reason in the UI. Reporting “sandbox unavailable: ” instead of returning no
    exit status would make this self-diagnosing.

IMPACT

Items 1 and 2 affect every RHEL, Rocky, AlmaLinux and Fedora host, since the symlinked CA bundle
comes from the standard ca-certificates package. Item 3 affects any setup with an NFS-shared home
directory. Combined with a kernel older than 6.2, which covers all of RHEL 9, there is no usable
sandbox backend and the agent cannot run commands at all.

WORKAROUND

Disabling sandboxing in Settings → Agents → Approvals & Execution restores functionality.

Note that a workspace-level and a user-level ~/.cursor/sandbox.json containing
{“type”: “insecure_none”} were both created on the remote host and had no effect across several
window reloads and a full server restart. Only the client-side setting worked. If sandbox.json is
intended to be read on the remote host in a remote-SSH session, that is a separate bug. If it is
client-side only, the sandbox.json reference docs should say so explicitly.

Does this stop you from using Cursor

No - Cursor works, but with this issue

Hey there,
There isn’t a good workaround today that keeps the sandbox on - the failing paths aren’t user-configurable, and sandbox.json on the remote isn’t loaded in Remote SSH. One practical step in the meantime: update to a 3.13.x build - same underlying issue, but you’ll get a clearer surfaced error instead of the silent hang.

We’ve let the team know and this is an issue we’re tracking. I’ll post here when there’s an update.

Hello, is there any progress with this bug?

Our team is looking into this, but there’s no shipped update yet and I don’t have a timeline. Until then, turning sandboxing off under Settings > Agents > Approvals & Execution is what unblocks agent commands. If that page is locked by a team admin, they’ll need to change it.

Hi Mohit,

Can you please share detailed steps for the workaround? Switching Run Mode to “Run Everything (Unsandboxed)” doesn’t help. Note I use Remote SSH, do I need additional settings to turn off sandbox in this case?

Thanks,

Yaroslav