Skip to content

[Bug]: Inline env var prefix (e.g. CI=true git commit) bypasses bash permission rules #16075

@fazzledev

Description

@fazzledev

Description

Commands with inline environment variable prefixes (e.g. CI=true git commit) bypass bash permission rules. A user who has configured "git *": "ask" will not be prompted — the command executes silently.

This affects any inline env var prefix, not just CI=true. FOO=bar git commit, ANYTHING=1 git push — all bypass the pattern match.

Root Cause

Introduced in commit e7ff714 (2026-01-30): "fix: handle redirected_statement treesitter node in bash permissions (#6737)"

In packages/opencode/src/tool/bash.ts, line 97:

let commandText = node.parent?.type === "redirected_statement" ? node.parent.text : node.text

node.text returns the full text of the command AST node, including any variable_assignment children. So for CI=true git commit -m "msg", commandText becomes "CI=true git commit -m \"msg\"".

Then on line 139:

patterns.add(commandText)  // "CI=true git commit -m \"msg\""

The permission system then tries to match "CI=true git commit -m \"msg\"" against the configured rule "git *"no match — and falls through to "*": "allow", so the command runs without a dialog.

Meanwhile, the command[] array (used for always) correctly strips variable_assignment children (the loop on lines 100–113 only includes command_name, word, string, raw_string, concatenation node types). So command[0] = "git" is correct — but it's not used for the patterns.add() that drives permission matching.

Before the offending commit

The previous code was:

patterns.add(command.join(" "))  // "git commit -m msg" ← correctly stripped

This correctly matched "git *" regardless of any inline env var prefix.

The change broke it

The commit changed patterns.add(command.join(" ")) to patterns.add(commandText) to fix redirect handling (so users see git commit 2>&1 in the permission dialog instead of just git commit). The redirect fix is valid, but it unintentionally included variable_assignment nodes in the pattern used for permission matching.

Steps to Reproduce

  1. Configure opencode.json:
{
  "permission": {
    "bash": {
      "git *": "ask",
      "*": "allow"
    }
  }
}
  1. Have an AI agent run: CI=true git commit --allow-empty -m "test"
  2. Expected: Permission dialog fires for git commit
  3. Actual: Command executes silently — no dialog

Works with any inline env var: FOO=bar git commit, GIT_AUTHOR_NAME=x git commit, etc.

Note: export CI=true; git commit (separate commands) is not affected — only the inline VAR=value command syntax.

Environment

  • OpenCode version: 1.1.51 (bug present, introduced in 1.1.x around 2026-01-30)
  • Confirmed via binary strings extraction and source code analysis
  • Affects all platforms

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions