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
Observed in source at commits baef5cd43b and 743f6410f2, current dev branch (code-verified; see References below)
Steps to reproduce
Set permission: { bash: "deny" }.
Prompt the agent with (a) env git status, (b) echo > ~/.ssh/authorized_keys style args, (c) python3 -c "<code that writes outside worktree>", (d) a project-local ./script.sh (CWD exception).
Observe prompts/denials are skipped or inconsistent: CWD-resolved executables are implicitly permitted, and argv-code gadgets (python3 -c, cargo install, node -e) are not path-scored by the FILES list (packages/opencode/src/tool/shell.ts:30-53).
Screenshot and/or share link
N/A — verified against source (details and file:line references below).
Operating System
All (cross-platform; verified on macOS Darwin)
Details
Two adjacent gaps in the shell permission scanner are unreported on their own merits (they currently only exist as fragments inside other issues):
CWD exception defeats deny-all. The scanner treats any command whose executable resolves inside the working directory (project-local binaries, ./scripts/*) as implicitly permitted — shell.ts:30 sets CWD, and the path check exempts project-relative executables. A malicious repo can drop ./script.sh (checked in or fetched during install), and the deny-all user gets no prompt and no denial: the agent runs it unchecked. A repo-controlled file executing with the user's session privileges is the worst-case shape for agentic malware — and it does not require a bypass "trick" at all, it falls out of the documented permission model.
FILES-list validation is keyed on argc position, not on what the binary does. The tool's FILES list (shell.ts:31-53) path-validates arguments it scores as file paths (e.g. positional args to echo, python3, cargo), but the plumbing covers neither:
stdout gadgets:echo/printf/cat writing in-band is harmless, but python3 -c "..." and cargo run/cargo install/node -e take code in arguments that are not path-scored, so they are checked against no path rules at all — yet they can write anywhere (devices, /etc, $HOME/.ssh) and read anything into stdout.
env-var execution:env git status (and friends: VAR=1 cmd) execute a command that the scanner never parses from the argument list; VERSION=1 npm run x etc. all re-exec with the env prefix. Whether the inner command is then checked depends on the parser's handling of the leading tokens — observed behavior is inconsistent and depends on the argument shape, i.e. the same logical action is permitted or denied based on cosmetic differences.
Net effect: permission: { bash: deny } (or any rule set) is effectively bypassable by trivial rewording, as independently reproduced 11/11 ways in #39931-related discussions — the parser never sees the actual executed program for these shapes.
Suggested fix
Parse the command with the same grammar the shell uses: strip env-prefix assignments and expansions (env, VAR=x), resolve PATH-style lookups, then evaluate the effective command — not the raw argv.
Treat CWD-resolved executables as permission-checked like any external binary, or explicitly require a capability flag for project-binary execution.
Path-check code that executes code: python3, node, cargo, ruby, perl invocations should be evaluated for what they can touch (heredocs, -c, install targets), matching the existing redirection-target direction of travel (Shell redirect targets bypass the external_directory permission #32628).
Plugins
None required
OpenCode version
Observed in source at commits baef5cd43b and 743f6410f2, current dev branch (code-verified; file:line references in Details).
Screenshot and/or share link
N/A — verified against source (details and file:line references below).
Operating System
All (cross-platform; verified on macOS Darwin).
Steps to reproduce
Set permission: { bash: "deny" }.
Prompt the agent with (a) env git status, (b) stdout/write gadgets such as echo > ~/.ssh/authorized_keys or python3 -c "<code that writes outside the worktree>", (c) a project-local ./script.sh (CWD exception).
Observe prompts/denials are skipped or inconsistent: CWD-resolved executables are implicitly permitted, and argv-code gadgets (python3 -c, cargo install, node -e) are not path-scored by the FILES list (packages/opencode/src/tool/shell.ts:30-53).
[SECURITY] Shell permission: CWD exception + stdout/write gadgets (echo/python3/cargo) defeat permission prompts and
denyrulesDescription
Description
permission: denyadvisory)tool/shell.ts(verified atbaef5cd43b; redirection gap still present at743f6410f2)--double hyphen #39931 (--parse-error bypass, open), Shell redirect targets bypass the external_directory permission #32628 (redirect targets, open), Permission system: bash commands can create files outside permitted directories #18396 (subprocess side-effects, auto-closed), refactor(core): detect external command paths with a bash parser #38822 (exec-path parser refactor, auto-closed unmerged), AI circumvents constraints #38807Plugins
None required
OpenCode version
Observed in source at commits
baef5cd43band743f6410f2, currentdevbranch (code-verified; see References below)Steps to reproduce
permission: { bash: "deny" }.env git status, (b)echo > ~/.ssh/authorized_keysstyle args, (c)python3 -c "<code that writes outside worktree>", (d) a project-local./script.sh(CWD exception).python3 -c,cargo install,node -e) are not path-scored by the FILES list (packages/opencode/src/tool/shell.ts:30-53).Screenshot and/or share link
N/A — verified against source (details and file:line references below).
Operating System
All (cross-platform; verified on macOS Darwin)
Details
Two adjacent gaps in the shell permission scanner are unreported on their own merits (they currently only exist as fragments inside other issues):
CWD exception defeats deny-all. The scanner treats any command whose executable resolves inside the working directory (project-local binaries,
./scripts/*) as implicitly permitted —shell.ts:30sets CWD, and the path check exempts project-relative executables. A malicious repo can drop./script.sh(checked in or fetched during install), and the deny-all user gets no prompt and no denial: the agent runs it unchecked. A repo-controlled file executing with the user's session privileges is the worst-case shape for agentic malware — and it does not require a bypass "trick" at all, it falls out of the documented permission model.FILES-list validation is keyed on argc position, not on what the binary does. The tool's FILES list (
shell.ts:31-53) path-validates arguments it scores as file paths (e.g. positional args toecho,python3,cargo), but the plumbing covers neither:echo/printf/catwriting in-band is harmless, butpython3 -c "..."andcargo run/cargo install/node -etake code in arguments that are not path-scored, so they are checked against no path rules at all — yet they can write anywhere (devices,/etc,$HOME/.ssh) and read anything into stdout.env git status(and friends:VAR=1 cmd) execute a command that the scanner never parses from the argument list;VERSION=1 npm run xetc. all re-exec with the env prefix. Whether the inner command is then checked depends on the parser's handling of the leading tokens — observed behavior is inconsistent and depends on the argument shape, i.e. the same logical action is permitted or denied based on cosmetic differences.Net effect:
permission: { bash: deny }(or any rule set) is effectively bypassable by trivial rewording, as independently reproduced 11/11 ways in #39931-related discussions — the parser never sees the actual executed program for these shapes.Suggested fix
env,VAR=x), resolvePATH-style lookups, then evaluate the effective command — not the raw argv.python3,node,cargo,ruby,perlinvocations should be evaluated for what they can touch (heredocs,-c, install targets), matching the existing redirection-target direction of travel (Shell redirect targets bypass the external_directory permission #32628).Plugins
None required
OpenCode version
Observed in source at commits
baef5cd43band743f6410f2, currentdevbranch (code-verified; file:line references in Details).Screenshot and/or share link
N/A — verified against source (details and file:line references below).
Operating System
All (cross-platform; verified on macOS Darwin).
Steps to reproduce
permission: { bash: "deny" }.env git status, (b) stdout/write gadgets such asecho > ~/.ssh/authorized_keysorpython3 -c "<code that writes outside the worktree>", (c) a project-local./script.sh(CWD exception).python3 -c,cargo install,node -e) are not path-scored by the FILES list (packages/opencode/src/tool/shell.ts:30-53).Details