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
i got prompt for "Permission required" / "Shell command".
the command is something like PYTHONPATH=...somepath uv run ...
i press "Allow always", then i get prompt "will allow ... uv *"
However uv * is allowed in my opencode.json
I suspect that the env variable prefix is not part of the mathcing process, but when opencode tries to determine what to give permisson to, it does identify uv as base command, yet it should then do a 2nd lookup
to see if it has permissions for it. And only in case it does not have the permissions, only then start this interactive process
reproducer is easy: look for shell command that is allowed in config, and that has simple output. then do the followin. in my case it is uv (i have uv * allowed), and it has simple invocation is uv --version (to show the version)
in the opencode session
ask to "run uv --version" -> works without prompting
i expect step two to also pass without prompt; this is also teh case when using combined commands
when asked to "run uv --version && python --version i get same promtp (i guess the * does not match && or ; etc), and then it asks to give permission to both uv * and python --version *. i expect that the first uv * is derived from already allowed permissions, and only prompts for commands it has not rights for
Pressing "always" in the prompt offers python3 * (normalized, env prefix dropped), so the prompt recurs for the same command. The matching rule is strict on the raw command text, while the always-button proposes a normalized base command — the two never line up:
// matcher: compares the raw resource text
resource: _.text.trim()// "PYTHONPATH=src python3 --version"// always-button: proposes a normalized prefix
save: Ek(x).join(" ")+" *"// -> ["python3 *"] (prefix dropped)
So python3 * cannot match PYTHONPATH=src python3 ..., and a config rule python3 * does not match it either (the issue reporter's uv * case is the same).
Consistency check from the matcher itself: set * matches set -e, and a multilinepython3 ... is matched by python3 *. These comparisons isolate the inline env-assignment prefix rather than multiline arguments.
Local workaround tested (config-only, no code change): the following rule after "*": "ask":
Verified empirically with separate tool calls and an SSE permission.asked detector: PYTHONPATH=src python3 --version and PYTHONPATH=src python3 -c ... executed without an ask, before a new plain-Python approval was saved. No new saved approvals were created by these two config-allowed probes. Plain python3 --version initially went through ask; its approval reply subsequently saved python3 * for the test project.
Correction after review — scope and test limitations: this glob is not a narrow executable/env boundary. Its first * matches spaces and arbitrary text. Checks with the installed matcher, without executing the example commands, also matched:
PYTHONPATH=src OTHER_VAR=1 python3 --version
PYTHONPATH=src sh -c : python3 ignored
The second example invokes sh, not Python; python3 is only an argument. The scanner retains the raw command-node text, so matching a textual suffix does not constrain the executable. Additional env assignments, including security-sensitive ones, can also be covered. My earlier "narrow rule" / "does not over-match" claims were incorrect.
The negative control was actually SOME_TEST_VAR=1 uname -a; echo "exit=$?"; date +%s.%N. Its aggregate ask could have been caused by another segment, so it does not independently prove that the uname resource resolved to ask. That control needs a standalone rerun.
A more constrained candidate for this exact use case is PYTHONPATH=src python3 *, with the PYTHONPATH value fixed rather than wildcarded. This candidate has not been runtime-verified in the above tests; other trusted values would need explicit rules.
Upstream direction: make the proposed saved pattern match the resource that caused the ask while preserving the intended env-assignment and executable boundaries. A raw-prefix proposal should not automatically wildcard those boundaries. A second authorization lookup on the normalized base command would instead change permission-checking semantics and could allow additional env-prefixed commands; it is not merely a proposal-side/UI fix and needs a separate security decision.
@thdxr this is still present in v2 as mentioned by @zenv-dev (for 2.0.24) and also tested by myself with 2.0.27
i don't have the permission to reopen this issue
@zenv-dev if i understand you correctly, you are right that the prefix handling and the composed commands are fundamentally different; but i don't follow you 100% how you tackle the solution (i might also read the PR wrong ;).
i would assume that any shell command to be executed is parsed (eg by tree-splitter) in all possible base commands, and each is always checked if the it has the required permissions. and only the missing ones are prompted back to the user.
the prefix part is a bit different imho, but in the new v2 config it might make sense to add a "prefix" option to the permissiosn list, wheter or not to allow certain prefixes.
Activity
stdweird commentedon Aug 28, 2026
reproducer is easy: look for shell command that is allowed in config, and that has simple output. then do the followin. in my case it is
uv(i haveuv *allowed), and it has simple invocation isuv --version(to show the version)in the opencode session
uv --version" -> works without promptingABC=def uv --version" -> throws prompt, sellect allow always, etc etci expect step two to also pass without prompt; this is also teh case when using combined commands
when asked to "run
uv --version && python --versioni get same promtp (i guess the*does not match&∨etc), and then it asks to give permission to bothuv *andpython --version *. i expect that the firstuv *is derived from already allowed permissions, and only prompts for commands it has not rights forzenv-dev commentedon Oct 7, 2026
Reproduced the same asymmetry on v2.0.24 (the raw-vs-normalized matcher split).
Repro (config has
"bash": { "*": "ask", ... }, noPYTHONPATH=...rule):PYTHONPATH=src python3 --version # -> "Permission required" promptPressing "always" in the prompt offers
python3 *(normalized, env prefix dropped), so the prompt recurs for the same command. The matching rule is strict on the raw command text, while the always-button proposes a normalized base command — the two never line up:So
python3 *cannot matchPYTHONPATH=src python3 ..., and a config rulepython3 *does not match it either (the issue reporter'suv *case is the same).Consistency check from the matcher itself:
set *matchesset -e, and a multilinepython3 ...is matched bypython3 *. These comparisons isolate the inline env-assignment prefix rather than multiline arguments.Local workaround tested (config-only, no code change): the following rule after
"*": "ask":Verified empirically with separate tool calls and an SSE
permission.askeddetector:PYTHONPATH=src python3 --versionandPYTHONPATH=src python3 -c ...executed without an ask, before a new plain-Python approval was saved. No new saved approvals were created by these two config-allowed probes. Plainpython3 --versioninitially went through ask; its approval reply subsequently savedpython3 *for the test project.Correction after review — scope and test limitations: this glob is not a narrow executable/env boundary. Its first
*matches spaces and arbitrary text. Checks with the installed matcher, without executing the example commands, also matched:PYTHONPATH=src OTHER_VAR=1 python3 --version PYTHONPATH=src sh -c : python3 ignoredThe second example invokes
sh, not Python;python3is only an argument. The scanner retains the raw command-node text, so matching a textual suffix does not constrain the executable. Additional env assignments, including security-sensitive ones, can also be covered. My earlier "narrow rule" / "does not over-match" claims were incorrect.The negative control was actually
SOME_TEST_VAR=1 uname -a; echo "exit=$?"; date +%s.%N. Its aggregate ask could have been caused by another segment, so it does not independently prove that theunameresource resolved to ask. That control needs a standalone rerun.A more constrained candidate for this exact use case is
PYTHONPATH=src python3 *, with the PYTHONPATH value fixed rather than wildcarded. This candidate has not been runtime-verified in the above tests; other trusted values would need explicit rules.Upstream direction: make the proposed saved pattern match the resource that caused the ask while preserving the intended env-assignment and executable boundaries. A raw-prefix proposal should not automatically wildcard those boundaries. A second authorization lookup on the normalized base command would instead change permission-checking semantics and could allow additional env-prefixed commands; it is not merely a proposal-side/UI fix and needs a separate security decision.
thdxr commentedon Oct 11, 2026
Thanks for the report! OpenCode 2.0 is now out and development is focused on V2, so we're closing issues filed against OpenCode 1. Please upgrade (
opencode upgrade --major, details: https://anoma.ly/notes/opencode-2-0), and if this is still relevant on 2.0, reopen this issue or open a new one with your 2.0 version.— from 𝕺𝖕𝖊𝖓𝕮𝖔𝖉𝖊
stdweird commentedon Oct 13, 2026
@thdxr this is still present in v2 as mentioned by @zenv-dev (for 2.0.24) and also tested by myself with 2.0.27
i don't have the permission to reopen this issue
stdweird commentedon Oct 13, 2026
@zenv-dev if i understand you correctly, you are right that the prefix handling and the composed commands are fundamentally different; but i don't follow you 100% how you tackle the solution (i might also read the PR wrong ;).
i would assume that any shell command to be executed is parsed (eg by tree-splitter) in all possible base commands, and each is always checked if the it has the required permissions. and only the missing ones are prompted back to the user.
the prefix part is a bit different imho, but in the new v2 config it might make sense to add a
"prefix"option to the permissiosn list, wheter or not to allow certain prefixes.