Sandbox .cursorignore bypass: tracked ignored files readable via git object store

Where does the bug appear (feature/product)?

Cursor IDE

Describe the Bug

Inside the Allowlist sandbox (Linux DevContainer), a file listed in .cursorignore is correctly hidden as a working-tree path (0-byte read-only blackhole mount) and is blocked by Cursor’s built-in Read/Grep tools. However, if the file is tracked in Git, its committed content remains fully readable without any approval through the Git object database, e.g.:

git show HEAD:path/to/ignored/file

git show reads from .git/objects, not from the (blackholed) working-tree path, so the sandbox filesystem restriction does not apply. This contradicts the documented sandbox guarantee that ignored files are “completely inaccessible to the sandboxed process” and that “any process inside the sandbox” sees the same restricted filesystem view.

The Git binary is not even required: loose objects and packfiles under .git/objects are ordinary readable files and can be decompressed directly (e.g. a few lines of Python + zlib). Any command-text-based filter (allowlist, hook matcher) is therefore insufficient by design.

Scope of the user-side mitigation is also incomplete. Adding ".git/objects/" to .cursorignore closes the main-repository path, but it does not cover submodule object stores under .git/modules/. In a repository with a submodule, the same bypass remains fully open via the submodule’s object store, while the main repository is blocked. (Note: blocking “.git/**” entirely is not a viable workaround because the sandbox then fails to start, as it needs to mount .git/hooks read-only.)

Steps to Reproduce

Environment:

  • Cursor >= 3.10.20
  • Allowlist (with Sandbox)
  • Linux DevContainer
  • Git-backed workspace

Preconditions:

  • Git-backed workspace
  • File is tracked and present in a reachable Git object
  • File path matches .cursorignore
  • Agent shell command runs in the sandbox

Minimal reproduction:

  1. Commit a file containing a test-only marker.
  2. Add its path to .cursorignore.
  3. Confirm that cat path and Cursor Read fail or return the blackhole.
  4. Run: git show HEAD:path
  5. Observe that the marker is returned without an out-of-sandbox approval.

Alternative exploitation:
The Git executable is not required; loose objects and packfiles are ordinary readable files and can be parsed directly.

Expected Behavior

Content governed by .cursorignore should be inaccessible to any process running inside the sandbox, regardless of the representation used to reach it, not only the working-tree pathname. In particular, reading the same bytes through the git object database (git show / git cat-file / git archive, or direct reads of .git/objects packfiles) should be subject to the same restriction as reading the working-tree path.

Operating System

MacOS

Version Information

Version: 3.11.13 (Universal)
VS Code Extension API: 1.125.0
Commit: 3f21b08f0b436a07be29fbfe00b304fa15553350
Date: 2026-07-10T01:45:28.254Z
Layout: IDE
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

Is this known/intended behavior, i.e. is .cursorignore enforcement in the sandbox scoped to working-tree paths only and NOT to the Git object store?

If intended, is the recommended approach for us to prevent Git object access in the DevContainer (e.g. our current workaround of adding .git/objects/** and .git/modules/** for submodules to .cursorignore), or is there a supported mechanism we are missing?

Does this stop you from using Cursor

No - Cursor works, but with this issue

Hey there,

You’ve read it right: today the sandbox applies .cursorignore at the working-tree path level, so it doesn’t yet extend to Git’s object store - which is why a tracked file can still be reached via git show (or a direct .git/objects read). That’s a coverage gap on our side, not your setup, and I’ve flagged it with the team to extend.

Your workaround is the right approach: keep .git/objects/** and, for submodules, .git/modules/** in .cursorignore (that submodule gap is real). Don’t block all of .git/** — the sandbox needs a few .git paths to start.

For your evaluation, I’d treat .cursorignore + sandbox as a strong guardrail rather than a hard boundary; for the most sensitive values, keeping them out of committed history is the safest bet. Reference: Ignore files.

I’ll follow up here as we extend this.

Hi Mohit,

Thanks for confirming that this is a coverage gap and that the submodule path must be covered as well.

We appreciate you looking into it and will keep an eye out for further updates.