.cursorignore sandbox exclusions may fail with very large ignored file trees

Where does the bug appear (feature/product)?

Cursor IDE

Describe the Bug

I have been testing Cursor’s Sandbox behavior with .cursorignore and noticed behavior that looks unexpected when the workspace contains a very large number of generated files and directories.

In my test setup, I generated a large filesystem structure using a script. The workspace currently contains:

  • 19,545 directories
  • 585,776 files

I then tested sandbox access to one specific file. When only that specific file was listed in .cursorignore, sandbox access was denied as expected.

However, when I added a broad ignore pattern using **, access to the same file was unexpectedly allowed again.

I am not sure whether this is a known limitation, a documentation gap, or a bug in the sandbox file override mechanism.

Steps to Reproduce

The file used in my test was:
v5/5/5/5/5/5/5-5-5-5-5-Utils.java2

The actual content of the file was:
This is a secret! 5-5-5-5-5-Utils.java2

Scenario 1: Empty .cursorignore

.cursorignore is empty.

Prompt to the agent:

/shell cat v5/5/5/5/5/5/5-5-5-5-5-Utils.java2

Output:

$ cat v5/5/5/5/5/5/5-5-5-5-5-Utils.java2
sandbox: starting sandbox application
[sandbox debug output]
sandbox: sandbox application completed successfully
This is a secret! 5-5-5-5-5-Utils.java2

This is expected, since the file is not ignored.

Scenario 2: One specific file is ignored

.cursorignore contains only this line:

v5/5/5/5/5/5/5-5-5-5-5-Utils.java2

Prompt to the agent:

/shell cat v5/5/5/5/5/5/5-5-5-5-5-Utils.java2

Output:

cat v5/5/5/5/5/5/5-5-5-5-5-Utils.java2
sandbox: starting sandbox application
[more sandbox debug output]
sandbox: sandbox application completed successfully
cat: v5/5/5/5/5/5/5-5-5-5-5-Utils.java2: Permission denied

This is also expected. The sandbox denies access to the explicitly ignored file.

Scenario 3: ** plus the same specific file

.cursorignore contains:

**
v5/5/5/5/5/5/5-5-5-5-5-Utils.java2

Prompt to the agent:
/shell cat v5/5/5/5/5/5/5-5-5-5-5-Utils.java2

Output:

cat v5/5/5/5/5/5/5-5-5-5-5-Utils.java2
sandbox: starting sandbox application
[more sandbox debug output]
sandbox: sandbox application completed successfully
This is a secret! 5-5-5-5-5-Utils.java2

This surprised me. I would have expected access to be denied, especially because the file is covered by ** and is also listed explicitly.

Expected Behavior

I would expect sandboxed commands to be unable to read files that are ignored by .cursorignore.

More specifically:

If a file is ignored through a broad pattern such as **, sandbox access should be denied.
If a file is listed explicitly, sandbox access should be denied.
Combining both should not make the file readable again.
If there are known limits around the number of ignored files or directories, those limits should ideally be documented.

Could the combination of ** and a very large generated file tree cause the sandbox file override mechanism to fail or silently skip exclusions?

Operating System

MacOS

Version Information

Version: 3.9.16 (Universal)
VS Code Extension API: 1.105.1
Commit: 042b3c1a4c53f2c3808067f519fbfc67b72cad80
Date: 2026-06-27T06:41:01.941Z
Layout: editor
Build Type: Stable
Release Track: Default
Electron: 40.10.3
Chromium: 144.0.7559.236
Node.js: 24.15.0
V8: 14.4.258.32-electron.0
xterm.js: 6.1.0-beta.256
OS: Darwin arm64 25.5.0

Additional Information

I’m running an ubunut based devcontainer on a macbook.

Does this stop you from using Cursor

Sometimes - I can sometimes use Cursor

Hi Simon! I dug into this and want to reproduce your exact setup so we can pin it down.

On a smaller generated tree (git-backed, same ** + explicitly-listed file), the sandbox correctly blocks the file for me every time, so this looks tied to the scale of your workspace rather than the pattern by itself. To reproduce it at your size, could you share:

  1. The script you used to generate the tree, so I can recreate the ~585k-file / 19.5k-directory structure.
  2. Your exact .cursorignore (verbatim), plus the full output of the sandboxed cat including the sandbox: lines you trimmed.
  3. Whether it still reproduces on your current version, and whether the same cat is readable on a much smaller copy of the tree or only at full size.

That’ll let me match your conditions exactly. In the meantime, two things you can rely on:

  • For sensitive files, list them (or their paths) explicitly rather than using a broad **. That’s the dependable pattern (your single-file test blocks correctly), and it also avoids the slow sandbox startup you ran into.
  • Cursor’s built-in tools (read, edit, grep, list) enforce .cursorignore regardless of the sandbox, so those paths stay covered either way.

Really appreciate how thoroughly you’ve tested this. I’ll follow up as soon as I can reproduce it on my end.

First of all, thank you very much for looking into this so carefully. I appreciate the attention this is getting.

I also want to apologize in case my earlier reproduction with a very large ignored file tree may have derailed the investigation a bit. I am still going to look into that scenario more closely, but after further testing I am no longer sure that the number of files is the main trigger. I was able to reproduce what looks like the same, or at least a very similar, behavior with a much smaller setup.

Updated minimal setup

devcontainer.json:

{
  "name": "${localWorkspaceFolderBasename}-devcontainer",
  "image": "mcr.microsoft.com/devcontainers/base:ubuntu24.04@sha256:6e5abd134eb1c2b747927487c3d59590bcc17815d5d7b3afd494e1be5de0f6b4",
   "privileged": true,
  "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}",
  "workspaceMount": "source=${localWorkspaceFolder},target=/workspaces/${localWorkspaceFolderBasename},type=bind,consistency=cached",
  "remoteUser": "vscode",
  "updateRemoteUserUID": true,
  "containerEnv": {
    "SBX_DEBUG": "1"
  }
 }

.cursorignore:

# Ignore everything
**
# This exclusion appears necessary. Without it, sandbox creation fails when trying to read the .git folder. However, it also seems to allow the sandbox to read illegal-file.md.
!/*
illegal-file.md

illegal-file.md:

you may not read this

Observed behavior

With the .cursorignore shown above, there seems to be a difference between the terminal-command access path and Cursor’s internal tools:

  • Accessing illegal-file.md via a terminal command, for example cat illegal-file.md, succeeds inside the sandbox.
  • Accessing the same file via Cursor’s internal Read tool does not succeed.

From my point of view, the internal Read tool behavior seems closer to what I would expect. Since illegal-file.md is explicitly ignored, I would not expect terminal commands running inside the sandbox to be able to read it either.

Full output of the terminal:

sandbox: starting sandbox application
sandbox: original UID=1000, GID=1000
sandbox: step 0/7: skipping pre-discovery (preflight mode)
sandbox: step 1-2/7: creating namespaces (network_isolated=true)
sandbox: newuidmap/newgidmap not found, using setgroups deny method
sandbox: creating namespaces (setgroups deny mode, network_isolated=true)
sandbox: writing uid_map: 0 1000 1
sandbox: writing gid_map: 0 1000 1
sandbox: switching to root in namespace (setresgid)
sandbox: switching to root in namespace (setresuid)
sandbox: step 2.5/7: setting up loopback interface
sandbox: step 3/7: remounting / as MS_PRIVATE
sandbox: step 4/7: applying mount denies
sandbox: applying device restrictions
sandbox: staged /dev/null
sandbox: staged /dev/zero
sandbox: staged /dev/full
sandbox: staged /dev/random
sandbox: staged /dev/urandom
sandbox: staged /dev/tty
sandbox: created minimal /dev (8 mounts)
sandbox: device restrictions applied, mounts=8
sandbox: socket isolation: hiding "/run" with empty tmpfs
sandbox: socket isolation: skipping "/var/run" (already mounted as "/run")
sandbox: socket directory isolation applied, mounts=1
sandbox: workspace suffix rules root="/workspaces/cursor-sandbox-behavior" applied=0 mounts_total=9 t=0ms
sandbox: file-suffix rules (pre-discovered) applied=0 mounts_total=9 t=0ms
sandbox: git hooks rules applied=0 mounts_total=9 t=0ms
sandbox: mount denies summary mounts_total=9 suffix_applied=0 file_suffix_applied=0 git_hooks_applied=0 symlink_targets_applied=0 glob_applied=0 total=1ms
sandbox: step 5/7: applying landlock
sandbox: landlock: required V3 access_rw=BitFlags<AccessFs>(0b111111111110010, WriteFile | RemoveDir | RemoveFile | MakeChar | MakeDir | MakeReg | MakeSock | MakeFifo | MakeBlock | MakeSym | Refer | Truncate)
sandbox: landlock: file-only access_rw=BitFlags<AccessFs>(0b100000000000010, WriteFile | Truncate)
sandbox: landlock: ruleset created successfully (V3 required)
sandbox: landlock: preparing rule for "/dev/null" (optional=true)
sandbox: landlock: "/dev/null" is_directory=false
sandbox: landlock: preparing rule for "/dev/zero" (optional=true)
sandbox: landlock: "/dev/zero" is_directory=false
sandbox: landlock: preparing rule for "/dev/random" (optional=true)
sandbox: landlock: "/dev/random" is_directory=false
sandbox: landlock: preparing rule for "/dev/urandom" (optional=true)
sandbox: landlock: "/dev/urandom" is_directory=false
sandbox: landlock: preparing rule for "/dev/shm" (optional=true)
sandbox: landlock: "/dev/shm" is_directory=true
sandbox: landlock: preparing rule for "/workspaces/cursor-sandbox-behavior" (optional=false)
sandbox: landlock: "/workspaces/cursor-sandbox-behavior" is_directory=true
sandbox: landlock: preparing rule for "/workspaces/cursor-sandbox-behavior" (optional=false)
sandbox: landlock: "/workspaces/cursor-sandbox-behavior" is_directory=true
sandbox: landlock: preparing rule for "/tmp" (optional=true)
sandbox: landlock: "/tmp" is_directory=true
sandbox: landlock: preparing rule for "/var/tmp" (optional=true)
sandbox: landlock: "/var/tmp" is_directory=true
sandbox: landlock: adding write-allow rule for "/dev/null" (is_dir=false, access=BitFlags<AccessFs>(0b100000000000010, WriteFile | Truncate))
sandbox: landlock: successfully added rule for "/dev/null"
sandbox: landlock: adding write-allow rule for "/dev/zero" (is_dir=false, access=BitFlags<AccessFs>(0b100000000000010, WriteFile | Truncate))
sandbox: landlock: successfully added rule for "/dev/zero"
sandbox: landlock: adding write-allow rule for "/dev/random" (is_dir=false, access=BitFlags<AccessFs>(0b100000000000010, WriteFile | Truncate))
sandbox: landlock: successfully added rule for "/dev/random"
sandbox: landlock: adding write-allow rule for "/dev/urandom" (is_dir=false, access=BitFlags<AccessFs>(0b100000000000010, WriteFile | Truncate))
sandbox: landlock: successfully added rule for "/dev/urandom"
sandbox: landlock: adding write-allow rule for "/dev/shm" (is_dir=true, access=BitFlags<AccessFs>(0b111111111110010, WriteFile | RemoveDir | RemoveFile | MakeChar | MakeDir | MakeReg | MakeSock | MakeFifo | MakeBlock | MakeSym | Refer | Truncate))
sandbox: landlock: successfully added rule for "/dev/shm"
sandbox: landlock: adding write-allow rule for "/workspaces/cursor-sandbox-behavior" (is_dir=true, access=BitFlags<AccessFs>(0b111111111110010, WriteFile | RemoveDir | RemoveFile | MakeChar | MakeDir | MakeReg | MakeSock | MakeFifo | MakeBlock | MakeSym | Refer | Truncate))
sandbox: landlock: successfully added rule for "/workspaces/cursor-sandbox-behavior"
sandbox: landlock: adding write-allow rule for "/workspaces/cursor-sandbox-behavior" (is_dir=true, access=BitFlags<AccessFs>(0b111111111110010, WriteFile | RemoveDir | RemoveFile | MakeChar | MakeDir | MakeReg | MakeSock | MakeFifo | MakeBlock | MakeSym | Refer | Truncate))
sandbox: landlock: successfully added rule for "/workspaces/cursor-sandbox-behavior"
sandbox: landlock: adding write-allow rule for "/tmp" (is_dir=true, access=BitFlags<AccessFs>(0b111111111110010, WriteFile | RemoveDir | RemoveFile | MakeChar | MakeDir | MakeReg | MakeSock | MakeFifo | MakeBlock | MakeSym | Refer | Truncate))
sandbox: landlock: successfully added rule for "/tmp"
sandbox: landlock: adding write-allow rule for "/var/tmp" (is_dir=true, access=BitFlags<AccessFs>(0b111111111110010, WriteFile | RemoveDir | RemoveFile | MakeChar | MakeDir | MakeReg | MakeSock | MakeFifo | MakeBlock | MakeSym | Refer | Truncate))
sandbox: landlock: successfully added rule for "/var/tmp"
sandbox: landlock: calling restrict_self() to enforce rules
sandbox: landlock: restrict_self() returned status=RestrictionStatus { ruleset: FullyEnforced, no_new_privs: true, landlock: Available { effective_abi: V6, kernel_abi: None } }
sandbox: landlock: ruleset fully enforced (effective: Available { effective_abi: V6, kernel_abi: None })
sandbox: landlock: CURSOR_SANDBOX_LANDLOCK_STATUS=fully_enforced
sandbox: landlock: filesystem write restrictions are now ACTIVE
sandbox: landlock: writes allowed ONLY to paths added above
sandbox: step 5.5/7: applying seccomp dangerous syscall block
sandbox: step 6/7: applying seccomp network block
sandbox: step 6.5/7: dropping bypass capabilities
sandbox: successfully dropped capabilities
sandbox: step 7/7: changing to working directory "/workspaces/cursor-sandbox-behavior"
sandbox: sandbox application completed successfully
sandbox: starting sandbox application
sandbox: original UID=1000, GID=1000
sandbox: step 0/7: pre-discovering files (before namespace)
sandbox: pre-discovering files before namespace creation
sandbox: pre-discovery: scanning git-backed workspace root
sandbox: pre-discovery: scanning workspace root for git hooks
sandbox: pre-discovery: scanning "/workspaces/cursor-sandbox-behavior" for git hooks
sandbox: pre-discovery: computing glob deny actions
sandbox: pre-discovery: filtered ignore mapping from 2 to 1 git-backed roots
sandbox: compute_glob_deny_actions (walker): planned_total=30 hide_dir=0 ro_dir=3 hide_file=0 ro_file=0 allow_rw=27 t=8ms
sandbox: pre-discovery: allowlist_paths=6
sandbox: pre-discovery: computing read-only deny actions
sandbox: compute_glob_deny_actions (walker): planned_total=5 hide_dir=1 ro_dir=0 hide_file=4 ro_file=0 allow_rw=0 t=12ms
sandbox: pre-discovery complete: suffix_files=2 git_hooks=1 glob_actions=35 symlink_targets=0 t=37ms
sandbox: step 1-2/7: creating namespaces (network_isolated=true)
sandbox: newuidmap/newgidmap not found, using setgroups deny method
sandbox: creating namespaces (setgroups deny mode, network_isolated=true)
sandbox: writing uid_map: 0 1000 1
sandbox: writing gid_map: 0 1000 1
sandbox: switching to root in namespace (setresgid)
sandbox: switching to root in namespace (setresuid)
sandbox: step 2.5/7: setting up loopback interface
sandbox: step 3/7: remounting / as MS_PRIVATE
sandbox: step 4/7: applying mount denies
sandbox: applying device restrictions
sandbox: staged /dev/null
sandbox: staged /dev/zero
sandbox: staged /dev/full
sandbox: staged /dev/random
sandbox: staged /dev/urandom
sandbox: staged /dev/tty
sandbox: created minimal /dev (8 mounts)
sandbox: device restrictions applied, mounts=8
sandbox: socket isolation: hiding "/run" with empty tmpfs
sandbox: socket isolation: skipping "/var/run" (already mounted as "/run")
sandbox: socket directory isolation applied, mounts=1
sandbox: workspace suffix rules root="/workspaces/cursor-sandbox-behavior" applied=0 mounts_total=9 t=0ms
sandbox: remount RO failed for "/workspaces/cursor-sandbox-behavior/.cursorignore": EPERM: Operation not permitted, trying mount_setattr
sandbox: remount RO failed for "/workspaces/cursor-sandbox-behavior/.git/config": EPERM: Operation not permitted, trying mount_setattr
sandbox: file-suffix rules (pre-discovered) applied=2 mounts_total=11 t=0ms
sandbox: remount RO failed for "/workspaces/cursor-sandbox-behavior/.git/hooks": EPERM: Operation not permitted, trying mount_setattr
sandbox: blocked git hooks dir: "/workspaces/cursor-sandbox-behavior/.git/hooks"
sandbox: git hooks rules applied=1 mounts_total=12 t=0ms
sandbox: remount RO failed for "/workspaces/cursor-sandbox-behavior/.devcontainer": EPERM: Operation not permitted, trying mount_setattr
sandbox: remount RO failed for "/workspaces/cursor-sandbox-behavior/.git": EPERM: Operation not permitted, trying mount_setattr
sandbox: remount RO failed for "/workspaces/cursor-sandbox-behavior/my-folder": EPERM: Operation not permitted, trying mount_setattr
sandbox: remount RW failed for "/workspaces/cursor-sandbox-behavior/.cursorignore": EPERM: Operation not permitted, trying mount_setattr clear RDONLY
sandbox: remount RW failed for "/workspaces/cursor-sandbox-behavior/.cursorignore_2_single-file": EPERM: Operation not permitted, trying mount_setattr clear RDONLY
sandbox: remount RW failed for "/workspaces/cursor-sandbox-behavior/.DS_Store": EPERM: Operation not permitted, trying mount_setattr clear RDONLY
sandbox: remount RW failed for "/workspaces/cursor-sandbox-behavior/.cursorignore_1_empty": EPERM: Operation not permitted, trying mount_setattr clear RDONLY
sandbox: remount RW failed for "/workspaces/cursor-sandbox-behavior/README.md": EPERM: Operation not permitted, trying mount_setattr clear RDONLY
sandbox: remount RW failed for "/workspaces/cursor-sandbox-behavior/.gitignore": EPERM: Operation not permitted, trying mount_setattr clear RDONLY
sandbox: remount RW failed for "/workspaces/cursor-sandbox-behavior/.devcontainer/.DS_Store": EPERM: Operation not permitted, trying mount_setattr clear RDONLY
sandbox: remount RW failed for "/workspaces/cursor-sandbox-behavior/.devcontainer/devcontainer.json": EPERM: Operation not permitted, trying mount_setattr clear RDONLY
sandbox: remount RW failed for "/workspaces/cursor-sandbox-behavior/.git/config": EPERM: Operation not permitted, trying mount_setattr clear RDONLY
sandbox: remount RW failed for "/workspaces/cursor-sandbox-behavior/.git/HEAD": EPERM: Operation not permitted, trying mount_setattr clear RDONLY
sandbox: remount RW failed for "/workspaces/cursor-sandbox-behavior/.git/description": EPERM: Operation not permitted, trying mount_setattr clear RDONLY
sandbox: remount RW failed for "/workspaces/cursor-sandbox-behavior/my-folder/illegal-file.md": EPERM: Operation not permitted, trying mount_setattr clear RDONLY
sandbox: remount RW failed for "/workspaces/cursor-sandbox-behavior/.git/info/exclude": EPERM: Operation not permitted, trying mount_setattr clear RDONLY
sandbox: remount RW failed for "/workspaces/cursor-sandbox-behavior/.git/hooks/commit-msg.sample": EPERM: Operation not permitted, trying mount_setattr clear RDONLY
sandbox: remount RW failed for "/workspaces/cursor-sandbox-behavior/.git/hooks/pre-rebase.sample": EPERM: Operation not permitted, trying mount_setattr clear RDONLY
sandbox: remount RW failed for "/workspaces/cursor-sandbox-behavior/.git/hooks/sendemail-validate.sample": EPERM: Operation not permitted, trying mount_setattr clear RDONLY
sandbox: remount RW failed for "/workspaces/cursor-sandbox-behavior/.git/hooks/pre-commit.sample": EPERM: Operation not permitted, trying mount_setattr clear RDONLY
sandbox: remount RW failed for "/workspaces/cursor-sandbox-behavior/.git/hooks/applypatch-msg.sample": EPERM: Operation not permitted, trying mount_setattr clear RDONLY
sandbox: remount RW failed for "/workspaces/cursor-sandbox-behavior/.git/hooks/fsmonitor-watchman.sample": EPERM: Operation not permitted, trying mount_setattr clear RDONLY
sandbox: remount RW failed for "/workspaces/cursor-sandbox-behavior/.git/hooks/pre-receive.sample": EPERM: Operation not permitted, trying mount_setattr clear RDONLY
sandbox: remount RW failed for "/workspaces/cursor-sandbox-behavior/.git/hooks/prepare-commit-msg.sample": EPERM: Operation not permitted, trying mount_setattr clear RDONLY
sandbox: remount RW failed for "/workspaces/cursor-sandbox-behavior/.git/hooks/post-update.sample": EPERM: Operation not permitted, trying mount_setattr clear RDONLY
sandbox: remount RW failed for "/workspaces/cursor-sandbox-behavior/.git/hooks/pre-merge-commit.sample": EPERM: Operation not permitted, trying mount_setattr clear RDONLY
sandbox: remount RW failed for "/workspaces/cursor-sandbox-behavior/.git/hooks/pre-applypatch.sample": EPERM: Operation not permitted, trying mount_setattr clear RDONLY
sandbox: remount RW failed for "/workspaces/cursor-sandbox-behavior/.git/hooks/pre-push.sample": EPERM: Operation not permitted, trying mount_setattr clear RDONLY
sandbox: remount RW failed for "/workspaces/cursor-sandbox-behavior/.git/hooks/update.sample": EPERM: Operation not permitted, trying mount_setattr clear RDONLY
sandbox: remount RW failed for "/workspaces/cursor-sandbox-behavior/.git/hooks/push-to-checkout.sample": EPERM: Operation not permitted, trying mount_setattr clear RDONLY
sandbox: remount RO failed for "/workspaces/cursor-sandbox-behavior/.cursorignore": EPERM: Operation not permitted, trying mount_setattr
sandbox: remount RO failed for "/workspaces/cursor-sandbox-behavior/.git/hooks": EPERM: Operation not permitted, trying mount_setattr
sandbox: remount RO failed for "/workspaces/cursor-sandbox-behavior/.git/config": EPERM: Operation not permitted, trying mount_setattr
sandbox: glob denies (pre-discovered) applied_total=35 hide_dir=0 ro_dir=4 hide_file=0 ro_file=4 allow_rw=27 mounts_total=47 t=0ms
sandbox: mount denies summary mounts_total=47 suffix_applied=0 file_suffix_applied=2 git_hooks_applied=1 symlink_targets_applied=0 glob_applied=35 total=0ms
sandbox: step 5/7: applying landlock
sandbox: landlock: required V3 access_rw=BitFlags<AccessFs>(0b111111111110010, WriteFile | RemoveDir | RemoveFile | MakeChar | MakeDir | MakeReg | MakeSock | MakeFifo | MakeBlock | MakeSym | Refer | Truncate)
sandbox: landlock: file-only access_rw=BitFlags<AccessFs>(0b100000000000010, WriteFile | Truncate)
sandbox: landlock: ruleset created successfully (V3 required)
sandbox: landlock: preparing rule for "/dev/null" (optional=true)
sandbox: landlock: "/dev/null" is_directory=false
sandbox: landlock: preparing rule for "/dev/zero" (optional=true)
sandbox: landlock: "/dev/zero" is_directory=false
sandbox: landlock: preparing rule for "/dev/random" (optional=true)
sandbox: landlock: "/dev/random" is_directory=false
sandbox: landlock: preparing rule for "/dev/urandom" (optional=true)
sandbox: landlock: "/dev/urandom" is_directory=false
sandbox: landlock: preparing rule for "/dev/shm" (optional=true)
sandbox: landlock: "/dev/shm" is_directory=true
sandbox: landlock: preparing rule for "/workspaces/cursor-sandbox-behavior" (optional=false)
sandbox: landlock: "/workspaces/cursor-sandbox-behavior" is_directory=true
sandbox: landlock: preparing rule for "/workspaces/cursor-sandbox-behavior" (optional=false)
sandbox: landlock: "/workspaces/cursor-sandbox-behavior" is_directory=true
sandbox: landlock: preparing rule for "/tmp" (optional=true)
sandbox: landlock: "/tmp" is_directory=true
sandbox: landlock: preparing rule for "/var/tmp" (optional=true)
sandbox: landlock: "/var/tmp" is_directory=true
sandbox: landlock: adding write-allow rule for "/dev/null" (is_dir=false, access=BitFlags<AccessFs>(0b100000000000010, WriteFile | Truncate))
sandbox: landlock: successfully added rule for "/dev/null"
sandbox: landlock: adding write-allow rule for "/dev/zero" (is_dir=false, access=BitFlags<AccessFs>(0b100000000000010, WriteFile | Truncate))
sandbox: landlock: successfully added rule for "/dev/zero"
sandbox: landlock: adding write-allow rule for "/dev/random" (is_dir=false, access=BitFlags<AccessFs>(0b100000000000010, WriteFile | Truncate))
sandbox: landlock: successfully added rule for "/dev/random"
sandbox: landlock: adding write-allow rule for "/dev/urandom" (is_dir=false, access=BitFlags<AccessFs>(0b100000000000010, WriteFile | Truncate))
sandbox: landlock: successfully added rule for "/dev/urandom"
sandbox: landlock: adding write-allow rule for "/dev/shm" (is_dir=true, access=BitFlags<AccessFs>(0b111111111110010, WriteFile | RemoveDir | RemoveFile | MakeChar | MakeDir | MakeReg | MakeSock | MakeFifo | MakeBlock | MakeSym | Refer | Truncate))
sandbox: landlock: successfully added rule for "/dev/shm"
sandbox: landlock: adding write-allow rule for "/workspaces/cursor-sandbox-behavior" (is_dir=true, access=BitFlags<AccessFs>(0b111111111110010, WriteFile | RemoveDir | RemoveFile | MakeChar | MakeDir | MakeReg | MakeSock | MakeFifo | MakeBlock | MakeSym | Refer | Truncate))
sandbox: landlock: successfully added rule for "/workspaces/cursor-sandbox-behavior"
sandbox: landlock: adding write-allow rule for "/workspaces/cursor-sandbox-behavior" (is_dir=true, access=BitFlags<AccessFs>(0b111111111110010, WriteFile | RemoveDir | RemoveFile | MakeChar | MakeDir | MakeReg | MakeSock | MakeFifo | MakeBlock | MakeSym | Refer | Truncate))
sandbox: landlock: successfully added rule for "/workspaces/cursor-sandbox-behavior"
sandbox: landlock: adding write-allow rule for "/tmp" (is_dir=true, access=BitFlags<AccessFs>(0b111111111110010, WriteFile | RemoveDir | RemoveFile | MakeChar | MakeDir | MakeReg | MakeSock | MakeFifo | MakeBlock | MakeSym | Refer | Truncate))
sandbox: landlock: successfully added rule for "/tmp"
sandbox: landlock: adding write-allow rule for "/var/tmp" (is_dir=true, access=BitFlags<AccessFs>(0b111111111110010, WriteFile | RemoveDir | RemoveFile | MakeChar | MakeDir | MakeReg | MakeSock | MakeFifo | MakeBlock | MakeSym | Refer | Truncate))
sandbox: landlock: successfully added rule for "/var/tmp"
sandbox: landlock: calling restrict_self() to enforce rules
sandbox: landlock: restrict_self() returned status=RestrictionStatus { ruleset: FullyEnforced, no_new_privs: true, landlock: Available { effective_abi: V6, kernel_abi: None } }
sandbox: landlock: ruleset fully enforced (effective: Available { effective_abi: V6, kernel_abi: None })
sandbox: landlock: CURSOR_SANDBOX_LANDLOCK_STATUS=fully_enforced
sandbox: landlock: filesystem write restrictions are now ACTIVE
sandbox: landlock: writes allowed ONLY to paths added above
sandbox: step 5.5/7: applying seccomp dangerous syscall block
sandbox: step 6/7: applying seccomp network block
sandbox: step 6.5/7: dropping bypass capabilities
sandbox: successfully dropped capabilities
sandbox: step 7/7: changing to working directory "/workspaces/cursor-sandbox-behavior"
sandbox: sandbox application completed successfully
you may not read this

Additional observation

If the .cursorignore only contains the global ignore rule plus the ignored file, the sandbox setup itself appears to fail because .git is also hidden.

For example, with this .cursorignore:

**
illegal-file.md

I get the following sandbox output:

sandbox: starting sandbox application
sandbox: original UID=1000, GID=1000
sandbox: step 0/7: skipping pre-discovery (preflight mode)
[omitted due: post is to long otherwise]
sandbox: successfully dropped capabilities
sandbox: step 7/7: changing to working directory "/workspaces/cursor-sandbox-behavior"
sandbox: sandbox application completed successfully
sandbox: starting sandbox application
sandbox: original UID=1000, GID=1000
sandbox: step 0/7: pre-discovering files (before namespace)
sandbox: pre-discovering files before namespace creation
sandbox: pre-discovery: scanning git-backed workspace root
sandbox: pre-discovery: scanning workspace root for git hooks
sandbox: pre-discovery: scanning "/workspaces/cursor-sandbox-behavior" for git hooks
sandbox: pre-discovery: computing glob deny actions
sandbox: pre-discovery: filtered ignore mapping from 2 to 1 git-backed roots
sandbox: compute_glob_deny_actions (walker): planned_total=9 hide_dir=2 ro_dir=0 hide_file=7 ro_file=0 allow_rw=0 t=11ms
sandbox: pre-discovery: allowlist_paths=6
sandbox: pre-discovery: computing read-only deny actions
sandbox: compute_glob_deny_actions (walker): planned_total=5 hide_dir=1 ro_dir=0 hide_file=4 ro_file=0 allow_rw=0 t=9ms
sandbox: pre-discovery complete: suffix_files=2 git_hooks=1 glob_actions=14 symlink_targets=0 t=41ms
sandbox: step 1-2/7: creating namespaces (network_isolated=true)
sandbox: newuidmap/newgidmap not found, using setgroups deny method
sandbox: creating namespaces (setgroups deny mode, network_isolated=true)
sandbox: writing uid_map: 0 1000 1
sandbox: writing gid_map: 0 1000 1
sandbox: switching to root in namespace (setresgid)
sandbox: switching to root in namespace (setresuid)
sandbox: step 2.5/7: setting up loopback interface
sandbox: step 3/7: remounting / as MS_PRIVATE
sandbox: step 4/7: applying mount denies
sandbox: applying device restrictions
sandbox: staged /dev/null
sandbox: staged /dev/zero
sandbox: staged /dev/full
sandbox: staged /dev/random
sandbox: staged /dev/urandom
sandbox: staged /dev/tty
sandbox: created minimal /dev (8 mounts)
sandbox: device restrictions applied, mounts=8
sandbox: socket isolation: hiding "/run" with empty tmpfs
sandbox: socket isolation: skipping "/var/run" (already mounted as "/run")
sandbox: socket directory isolation applied, mounts=1
sandbox: workspace suffix rules root="/workspaces/cursor-sandbox-behavior" applied=0 mounts_total=9 t=0ms
sandbox: remount RO failed for "/workspaces/cursor-sandbox-behavior/.cursorignore": EPERM: Operation not permitted, trying mount_setattr
sandbox: remount RO failed for "/workspaces/cursor-sandbox-behavior/.git/config": EPERM: Operation not permitted, trying mount_setattr
sandbox: file-suffix rules (pre-discovered) applied=2 mounts_total=11 t=0ms
sandbox: remount RO failed for "/workspaces/cursor-sandbox-behavior/.git/hooks": EPERM: Operation not permitted, trying mount_setattr
sandbox: blocked git hooks dir: "/workspaces/cursor-sandbox-behavior/.git/hooks"
sandbox: git hooks rules applied=1 mounts_total=12 t=0ms
sandbox: hiding directory with tmpfs "/workspaces/cursor-sandbox-behavior/.devcontainer"
sandbox: hiding directory with tmpfs "/workspaces/cursor-sandbox-behavior/.git"
sandbox: bind blackhole "/tmp/.everysphere_sbx_bh_5206/blackhole" -> "/workspaces/cursor-sandbox-behavior/README.md"
sandbox: bind blackhole "/tmp/.everysphere_sbx_bh_5206/blackhole" -> "/workspaces/cursor-sandbox-behavior/illegal-file.md"
sandbox: bind blackhole "/tmp/.everysphere_sbx_bh_5206/blackhole" -> "/workspaces/cursor-sandbox-behavior/.cursorignore"
sandbox: bind blackhole "/tmp/.everysphere_sbx_bh_5206/blackhole" -> "/workspaces/cursor-sandbox-behavior/.gitignore"
sandbox: bind blackhole "/tmp/.everysphere_sbx_bh_5206/blackhole" -> "/workspaces/cursor-sandbox-behavior/.cursorignore_2_single-file"
sandbox: bind blackhole "/tmp/.everysphere_sbx_bh_5206/blackhole" -> "/workspaces/cursor-sandbox-behavior/.DS_Store"
sandbox: bind blackhole "/tmp/.everysphere_sbx_bh_5206/blackhole" -> "/workspaces/cursor-sandbox-behavior/.cursorignore_1_empty"
sandbox: mount bind failed for "/workspaces/cursor-sandbox-behavior/.git/hooks": ENOENT: No such file or directory
sandbox: failed at step 4/7 (mount denies): IO error: Failed to mount "/workspaces/cursor-sandbox-behavior/.git/hooks" read-only: IO error: No such file or directory (os error 2)
Error: Failed to apply sandbox: IO error: Step 4/7 (mount denies) failed: IO error: Failed to mount "/workspaces/cursor-sandbox-behavior/.git/hooks" read-only: IO error: No such file or directory (os error 2)

My current interpretation

This now looks like two related issues to me:

  1. A broad ** ignore rule also hides .git, and that obviously to interfere with sandbox setup.
  2. Adding !/* seems to make sandbox setup work again, but then terminal commands can read illegal-file.md, while Cursor’s internal Read tool still cannot. Even if illegal-file.md is moved inside a folder (my-folder/illegal-file.md), read access through the terminal succeeds while accessing using the internal tool fails as expected.

So the current question is probably less about the size of the ignored tree and more about how .cursorignore rules are interpreted differently by the sandbox setup, terminal commands, and internal tools.

Please let me know if there is a better way to structure this reproduction. I will also continue testing the original large-file-tree case separately, but this smaller setup seems more useful as a starting point.