Repository navigation
Description
- Found: 2026-10-08, Cowright Plan 01-11 planning probe (installer guard C-02)
- Environment: OpenCode 1.18.35, Linux
Summary
permission.bash deny rules are wildcard patterns. OpenCode splits a bash call into its commands
and matches each command's own text against the patterns. That covers chains and substitutions:
with "npx *@opengsd/gsd-core*": "deny", both cd /tmp && npx @opengsd/gsd-core ... and
echo $(npx @opengsd/gsd-core ...) are denied. But a wrapper is a different command head, so the
same rule does not deny bash -c "npx @opengsd/gsd-core ...", sh -c "...",
FOO=1 npx @opengsd/gsd-core ..., env npx ..., /usr/bin/env npx ... or timeout 30 npx ....
A user who wants to keep a model from running one program has to list every wrapper as its own
pattern, scoped tightly enough not to block legitimate scripts. Interpreter one-liners
(node -e, python -c), scripts written and then run, and wrappers nobody thought of still pass.
Minimal repro
- In a scratch HOME, put
{"permission": {"bash": {"npx *@opengsd/gsd-core*": "deny"}}}into
~/.config/opencode/opencode.jsonc. opencode debug agent build --pure --tool bash --params '{"command": "npx --no --offline @opengsd/[email protected] --help", "description": "probe"}'
exits 1 with "The user has specified a rule which prevents you from using this specific tool
call". (--no --offlineand the nonexistent version keep the command harmless if it runs.)- The same call with
"command": "bash -c \"npx --no --offline @opengsd/[email protected] --help\""
exits 0 and runs the command. So doenv npx ...,FOO=1 npx ...andtimeout 30 npx ...
with the same arguments. Re-checked in a scratch HOME on 2026-10-08.
Expected
A deny rule written for a command also denies that command when it is run through a common wrapper
(bash -c, sh -c, env, a NAME=value prefix, timeout, nohup, exec, xargs), or the
docs say clearly that it does not.
Actual
Only the command's own text is matched, so the deny list has to name every wrapper. At planning
time, 18 patterns denied 14 of 15 probed forms; timeout 30 npx ... passed until it got a pattern
of its own.
Suggested fix
Match deny rules against the unwrapped inner command as well: strip known wrappers and
NAME=value prefixes, and parse bash -c and sh -c payloads the way the line is already split.
Alternatively, offer a rule form keyed on the executable plus an argument pattern
(for example {"exec": "npx", "args": "*@opengsd/gsd-core*"}) that the engine applies after
unwrapping.
Cowright workaround
scripts/patches/installer-guard.cjs writes 28 deny patterns: the runners and bins, plus one
pattern per wrapper, scoped to the package name (bash *@opengsd/gsd-core*,
env *@opengsd/gsd-core*, *=* npx *gsd-core*, timeout *@opengsd/gsd-core* and others).
Check C15 and the probe matrix prove them with 28 harmless canaries. The forms no pattern covers
are detected after the fact by the smoke Claude watch and the installer-call detector (Plan
01-10). The patterns must be re-proven on every OpenCode upgrade.
Evidence
scripts/patches/installer-guard.cjsheader (planning-time probe facts, OpenCode 1.18.35)docs/smoke/runs/2026-10-07/installer-guard-rehearsal.json(residual_bypasses)docs/smoke/runs/2026-10-07/installer-guard-probe.json(full matrix on the real HOME: 33 of 33
canary probes denied, 4 of 4 controls allowed)- tests
scripts/test/installer-guard.test.cjs,scripts/test/installer-guard-install.test.cjs
Activity
opencode-agent commentedon Oct 8, 2026
Thanks for the detailed write-up and the probe matrix!
This was reported on OpenCode 1.18.35, which is v1. v1 now only gets fixes for critical bugs (data loss, security problems, or breakage with no workaround). Bash permission patterns are a guardrail, not a sandbox, and you already have a working set of wrapper-scoped deny patterns. Because of that, this is unlikely to be changed in v1.
We'd encourage you to try v2 (
@opencode/cli), where active development happens. If the same wrapper bypass (bash -c,env,NAME=value,timeout, …) still gets past a deny rule there, please reply with the v2 version and the repro, and it can be looked at in the normal flow. Please also reply if you believe this is critical for v1.Related issues, for reference:
opencode-agent commentedon Oct 9, 2026
We haven't had a reply, so I'm closing this as not planned. The report is about OpenCode v1 (1.18.35). v1 only gets fixes for critical bugs, and this wrapper gap in bash permission patterns has a workaround (the wrapper-scoped deny patterns you already use).
If the same bypass (
bash -c,env,NAME=value,timeout, …) also gets past a deny rule on v2 (@opencode/cli), please open a new issue with the v2 version and your repro. Thanks again for the detailed probe matrix.