Skip to content

fix(sandbox): handle symlinks in allowed paths on Linux and macOS#102

Open
tito wants to merge 1 commit into
mainfrom
fix/symlink-allow-paths
Open

fix(sandbox): handle symlinks in allowed paths on Linux and macOS#102
tito wants to merge 1 commit into
mainfrom
fix/symlink-allow-paths

Conversation

@tito

@tito tito commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Symlinked allowRead/allowWrite entries previously broke inside the sandbox.

Linux (deny-by-default): only the resolved target was bound (symlink glob matches were silently skipped entirely), so programs opening the original link path got ENOENT. The link is now recreated with bwrap --symlink and its resolved target bound at its real path, so both the link path and realpath()-style access work. Applies to user allow paths, glob matches, and the default home paths (shell configs, ~/.config, ...). Denied symlinked paths now mask the resolved target so denied content cannot leak through the link.

macOS: Seatbelt evaluates resolved paths, so rules are now also emitted for resolved targets of symlinked shell configs, home caches, and glob matches. ExpandGlobPatterns moved to a platform-neutral file so glob expansion works on darwin instead of being stubbed out.

Symlinks inside allowed directories pointing outside them get their targets exposed read-only, controlled by the new filesystem.symlinkScan option: "shallow" (default, direct entries only, one readdir per allowed dir), "deep" (recursive, capped at 10k entries), or "off". The scan never
auto-exposes credential locations (SensitiveUserDirs: ~/.ssh, ~/.gnupg, ~/.aws, .env files, ...); those still require an explicit allowRead grant, and denyRead overrides anything the scan exposes.

Docs: new "Symlinks in Allowed Paths" section in configuration.md and a
troubleshooting entry.

Fixes #91

Symlinked allowRead/allowWrite entries previously broke inside the
sandbox: on Linux, deny-by-default mode bound only the resolved target
(or silently skipped symlink glob matches), so programs opening the
original link path got ENOENT. Recreate the link with bwrap --symlink
and bind its resolved target so both paths work. On macOS, emit
Seatbelt rules for resolved targets of symlinked shell configs, home
caches, and glob matches, since Seatbelt evaluates resolved paths.

Symlinks inside allowed directories that point outside them now get
their targets exposed read-only, controlled by the new
filesystem.symlinkScan option: "shallow" (default, direct entries
only), "deep" (recursive, capped), or "off". The scan never
auto-exposes credential locations (SensitiveUserDirs); those still
require an explicit allowRead grant, and denyRead continues to
override anything the scan exposes. Denied symlinked paths now mask
the resolved target so denied content cannot leak through the link.

ExpandGlobPatterns moved to a platform-neutral file so glob expansion
works on darwin instead of being stubbed out.

Fixes #91
@marmotz

marmotz commented Jun 20, 2026

Copy link
Copy Markdown

When will this PR be merged and released?

@tito

tito commented Jun 20, 2026

Copy link
Copy Markdown
Contributor Author

I needed it to be tested on mac but didn't got time yet. Will do my best

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bwrap doesn't recognize symlinks

2 participants