cfgaudit

Rules / CFG095

CFG095 committed .cursor/sandbox.json weakens the agent's execution sandbox

Severity: error (sandbox disabled, network posture inverted, credential/system/root grant) · warn (unbounded allow pattern, other outside-workspace write grant, shared build cache) OWASP: LLM03:2026 – Excessive Agency

What cfgaudit checks

Cursor 2.5 added .cursor/sandbox.json, the profile that bounds what agent-run commands may touch. cfgaudit reports a project file that widens it.

Finding Severity
type: "insecure_none" — documented as "disables the sandbox entirely" error
networkPolicy.default: "allow" — Cursor's documented default is deny error
additionalReadwritePaths naming a credential directory, the home directory or / error
additionalReadwritePaths naming a system directory (/etc, /usr, /bin, …) error
additionalReadonlyPaths naming a credential directory, the home directory or / error
networkPolicy.allow containing "*", "0.0.0.0/0", "::/0" warn
any other additionalReadwritePaths grant outside the workspace warn
enableSharedBuildCache: true warn

This is the sandbox-weakening family CFG022 covers for Claude Code, CFG061 for Gemini CLI and CFG064 for Codex, reached through Cursor's file. type: "insecure_none" is the direct analogue of Codex's sandbox_mode: danger-full-access.

Why a committed file is the finding

Cursor reads two sandbox files and merges them "with per-repo settings taking priority":

~/.cursor/sandbox.json              # all workspaces
<workspace>/.cursor/sandbox.json    # single workspace, per-repo

That sentence is the summary. The same reference's "How policies merge" section is field by field (#649):

Field Merge
additionalReadwritePaths, additionalReadonlyPaths unioned across sources
networkPolicy.allow unioned (unless a team-admin allowlist replaces the union)
networkPolicy.deny always unioned
networkPolicy.default "deny" wins over "allow"
disableTmpWrite, networkPolicyStrict true wins
readBoundary per-repo replaces per-user
additionalReadPaths per-repo replaces per-user, then the team-admin list is added

So a committed file adds paths and allowed hosts to every teammate's sandbox, flips networkPolicy.default for a teammate who has no file of their own (a teammate who wrote "deny" keeps it), and decides readBoundary and the Read Allowlist outright. type is not in the list, so the summary's per-repo priority applies to it.

The read boundary (Cursor 3.23+)

readBoundary is "system" by default; "workspace" asks before the agent reads outside the workspace. Because the repository's value replaces the user's, a committed "system" undoes a teammate's "workspace" (warn), and a credential directory, the home directory or the filesystem root in additionalReadPaths is read without asking (error).

Read-only grants are still findings

additionalReadonlyPaths cannot be used to write outside the workspace, so system directories there are not reported — reading /usr is unremarkable. A credential directory is different: read access is all an exfiltration path needs, so ~/.ssh or ~/.aws in the read-only list is an error just as it is in the read-write list.

What is deliberately not flagged

enableSharedBuildCache and why it is only warn

Cursor documents it as redirecting build-tool caches "to a shared tmpdir so sandboxed and unsandboxed commands share the same caches". That is a writable channel across the sandbox boundary by construction: what a sandboxed agent command writes into the cache is what a later unsandboxed command reads.

It is warn rather than error because the documentation describes it as a build-performance feature and makes no claim either way about the isolation consequence. The finding states the mechanism and lets a reviewer judge; asserting an exploit would go beyond what the reference supports.

Fix

{
  "type": "workspace_readwrite",
  "networkPolicy": {
    "default": "deny",
    "allow": ["registry.npmjs.org", "*.githubusercontent.com"]
  },
  "additionalReadwritePaths": ["./build-cache"]
}

Scope

Project scope only. A user's own ~/.cursor/sandbox.json is self-intentional — the same reason CFG093 stays off the per-user permissions file.

References

Documentation for cfgaudit 1.18.1. Source of this page · Rule implementation