You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The native macOS (Seatbelt) sandbox profile includes file-write* allow rules for Claude's lock/temp paths that use regex patterns without an end anchor. As a result, a sandboxed process can create arbitrary attacker-named files and directories directly in $HOME whose names begin with .claude.json.lock or .claude.json.tmp. — paths that are not part of the intended whitelist.
Affected code
sandbox, in the native (Seatbelt) profile generation (# 6. Claude lock dirs and atomic-write temp files in $HOME):
Note the contrast with the .claude.lock rules two lines above, which are correctly anchored (pair of ...lock$ + ...lock/).
PoC
Reproduced on macOS 27.0 (arm64), running inside the sandbox as an agent process:
$ printf'test'>"$HOME/.claude.json.lockx"# succeeds — should be denied
$ ls -la "$HOME/.claude.json.lockx"-rw-r--r-- 1 david staff 4 Sep 28 23:18 /Users/david/.claude.json.lockx
$ printf'test'>"$HOME/.claude.json.tmp.anything/nested"# directory creation also allowed under the prefix
$ printf'test'>"$HOME/just-a-test"# correctly denied (EPERM)
Other escape routes I tested and confirmed are still blocked, for context: symlink traversal from /tmp (Seatbelt resolves the real path), launchctl submit, and AppleEvent-based file moves via Finder.
Impact
A sandboxed agent (or prompt-injected process) can plant arbitrarily named files/dirs in $HOME, e.g. ~/.claude.json.lockevil, ~/.claude.json.lock-backup, or nested trees under those prefixes.
Names closely mimic real lock/temp files (~/.claude.json.lock, ~/.claude.json.tmp.*), which is convenient for hiding state or confusing tooling/users.
No arbitrary $HOME write: this does not widen the sandbox to arbitrary paths. Severity is low–medium, but it violates the profile's stated intent of whitelisting only Claude's exact lock/temp paths.
Suggested fix
Anchor the regexes the same way the .claude.lock pair does, e.g.:
# directory + its contentsprintf'(allow file-write* (regex #"^%s/\\.claude\\.json\\.lock(/|$)"))\n'"$(policy_quote "$HOME")"# flat temp files only, no directories under the prefixprintf'(allow file-write* (regex #"^%s/\\.claude\\.json\\.tmp\\.[^/]+$"))\n'"$(policy_quote "$HOME")"
Activity
nikvdp commentedon Sep 29, 2026
Thanks, fixed in #71