Skip to content

permission handling with env variables #45914

Closed as not planned
Closed as not planned

Description

@stdweird

Description

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

Plugins

OMO-slim, superpowers

OpenCode version

1.18.21 (try to use latest)

Steps to reproduce

Will try to come up with reproducer

Screenshot and/or share link

No response

Operating System

RHEL 9.8

Terminal

tmux over ssh

Activity

  1. stdweird commented on Aug 28, 2026

    @stdweird
    Author

    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

    1. ask to "run uv --version" -> works without prompting
    2. ask to "run ABC=def uv --version" -> throws prompt, sellect allow always, etc etc

    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

  2. zenv-dev commented on Oct 7, 2026

    @zenv-dev

    Reproduced the same asymmetry on v2.0.24 (the raw-vs-normalized matcher split).

    Repro (config has "bash": { "*": "ask", ... }, no PYTHONPATH=... rule):

    PYTHONPATH=src python3 --version        # -> "Permission required" prompt

    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 multiline python3 ... 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":

    "bash": {
      "*": "ask",
      "PYTHONPATH=* python3 *": "allow"
    }

    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.

  3. thdxr commented on Oct 11, 2026

    @thdxr
    Member

    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 𝕺𝖕𝖊𝖓𝕮𝖔𝖉𝖊

  4. stdweird commented on Oct 13, 2026

    @stdweird
    Author

    @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

  5. stdweird commented on Oct 13, 2026

    @stdweird
    Author

    @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.

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

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions