-
-
Notifications
You must be signed in to change notification settings - Fork 2
Description
Summary
cli/src/lib/init/local-ops.ts executes commands from the API server using shell: true. The current protections are string-based and could be bypassed by a sufficiently creative payload. Before sentry init exits experimental mode, we should add OS-level sandboxing.
Current protections
validateCommand() (line 140) — three layers of string validation:
- Shell metacharacter blocking — rejects commands containing
;,&&,||,|,`,$(,$, quotes, redirects (>,<), braces, globs, newlines, backslashes - Env var injection blocking — rejects commands where the first token contains
= - Dangerous executable blocklist — rejects 40+ executables (
rm,curl,sudo,ssh,bash,eval, etc.) but only checks the first token — e.g.npm exec -- rm -rf /would pass becausenpmis the primary executable
safePath() / path validation — prevents path traversal and symlink escapes outside the project root.
runSingleCommand() (line 426) — spawns via spawn(command, [], { shell: true, cwd, ... }) with a timeout and output truncation (64KB cap).
Gap
All protections are string-based pattern matching. The command still runs under shell: true with full user privileges. Potential bypasses:
- Package manager subcommands that execute arbitrary code (e.g.
npm exec, lifecycle scripts) - Unicode/encoding tricks that survive validation but are interpreted differently by the shell
- Future commands the server might send that don't match current patterns
Suggested hardening (Linux)
These are additive layers — the string validation remains as a fast first pass.
| Technique | How | Benefit |
|---|---|---|
Linux namespaces / unshare |
unshare --net --mount --pid wrapper |
Network isolation, mount isolation, PID isolation |
| Landlock LSM | Restrict filesystem access to project dir + node_modules + package manager cache | Prevents reads/writes outside expected paths even if shell escapes |
bubblewrap (bwrap) |
Lightweight sandbox with readonly / bind-mount, writable project dir only |
Strong filesystem + namespace isolation in one tool |
| Drop to restricted user | runuser / setuid to a no-login user for spawned commands |
Limits damage from any escape |
| Read-only filesystem mounts | Bind-mount / as read-only, whitelist project dir as writable |
Commands can't modify system files |
| Network namespace isolation | Empty network namespace for commands that don't need network (e.g. codemods) | Prevents data exfiltration |
--shell=false where possible |
For simple commands like npx @sentry/wizard, split into [executable, ...args] and avoid shell entirely |
Eliminates shell injection surface |
macOS considerations
macOS lacks namespaces/Landlock. Options are more limited:
sandbox-exec(deprecated but functional) with a restrictive profile- Avoid
shell: truewhere possible by splitting commands into argv arrays
Priority
Low — the current string validation is a reasonable defense for an experimental feature where commands originate from our own API server. This becomes more important if/when the command surface expands or the feature exits experimental.