Thanks to visit codestin.com
Credit goes to github.com

Skip to content

fix(shell): support safe descriptor redirects and attribute denial rule source - #14086

Open
maoxin1234 wants to merge 2 commits into
Kilo-Org:mainfrom
maoxin1234:fix/plan-agent-bash-redirect-permissions
Open

fix(shell): support safe descriptor redirects and attribute denial rule source#14086
maoxin1234 wants to merge 2 commits into
Kilo-Org:mainfrom
maoxin1234:fix/plan-agent-bash-redirect-permissions

Conversation

@maoxin1234

Copy link
Copy Markdown
Contributor

Description

Closes #14062.

When running read-only diagnostic commands with standard stderr redirects (such as ls -la ~/.kilo/plans 2>&1 or git status 2>&1) in plan mode (or other modes with readOnlyBash), the tool evaluation previously treated the entire redirected statement as a candidate pattern containing > and &. This caused:

  1. The command to match *>* (and *&*) in readOnlyBash, unconditionally denying safe diagnostic commands that do not write to files.
  2. The denial error message in DeniedError.message unconditionally claimed "The user has specified a rule which prevents you from using this specific tool call." even when the denial originated from built-in agent (action.source=agent) or global (action.source=global) policy, which confused users into thinking their own config caused the denial.

Fix

  1. In packages/opencode/src/tool/shell.ts:
    • Added isSafeDescriptorRedirect and onlySafeRedirects helpers to recognize safe file descriptor duplications and closures (2>&1, >&2, 1>&2, 2>&-, etc.) which do not write to files on disk.
    • For commands whose redirections are purely safe descriptor duplications, source(node) returns the base command text so permission rules evaluate against the underlying command without triggering *>* file-redirection blocks.
    • Commands with actual file redirections (e.g. ls > out.txt 2>&1) continue to be preserved and caught by *>* / marked access unknown.
  2. In packages/core/src/v1/permission.ts:
    • Updated DeniedError.message to accurately reflect rule provenance:
      • "This agent's policy prevents you from using this specific tool call..." when source === "agent"
      • "A global policy prevents you from using this specific tool call..." when source === "global"
      • "The user has specified a rule which prevents you from using this specific tool call..." when specified by the user or default fallback.

Testing

  • Added unit tests in packages/opencode/test/kilocode/permission/bash-redirect-permission.test.ts:
    • Verified DeniedError.message accurately attributes agent, global, and user sources.
    • Verified safe descriptor redirect 2>&1 strips the redirect from evaluated pattern while preserving base command.
    • Verified unsafe file redirect > out.txt preserves redirect in pattern to be caught by policy.
  • Ran all 120 permission tests in packages/opencode/test/kilocode/permission/ with bun test (all 120 passed).

Comment thread packages/opencode/src/tool/shell.ts Outdated

// kilocode_change start
function isSafeDescriptorRedirect(text: string): boolean {
return /^\d*\s*(?:>\s*&|<\s*&)\s*(?:\d+|-)$/.test(text.trim()) || /^&>\s*(?:\d+|-)$/.test(text.trim())

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[WARNING]: &>N / &>- are file redirects, not descriptor duplications

In bash, &>word always redirects both stdout and stderr to a file named by word. The descriptor-duplication special case only applies to the >&word form, and only when word is a number or - (bash manual, "Redirecting Standard Output and Standard Error"). So &>1, &>0, and &>- create files named 1, 0, and -, but the second alternative here classifies them as safe descriptor redirects.

That matters because source() now strips any redirect that passes this check: echo secret &>1 is evaluated as echo secret, so its pattern no longer contains > and no longer matches the *>* deny rule used by readOnlyBash. For cat file &>1, access() also reports "read". That is a permission bypass for writes to numeric/- filenames.

Every legitimate duplication (2>&1, >&2, <&0, 2>&-, ...) is already covered by the first alternative, so the &> branch can be dropped:

Suggested change
return /^\d*\s*(?:>\s*&|<\s*&)\s*(?:\d+|-)$/.test(text.trim()) || /^&>\s*(?:\d+|-)$/.test(text.trim())
return /^\d*\s*(?:>\s*&|<\s*&)\s*(?:\d+|-)$/.test(text.trim())

Reply with @kilocode-bot fix it to have Kilo Code address this issue.


function source(node: Node) {
return (node.parent?.type === "redirected_statement" ? node.parent.text : node.text).trim()
if (node.parent?.type === "redirected_statement" && !onlySafeRedirects(node.parent)) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[SUGGESTION]: Missing changeset for a user-visible fix

This PR changes user-facing behavior: read-only/plan mode now accepts safe descriptor redirects like 2>&1, and denial messages now attribute agent/global policy. No .changeset/*.md file is included. Per repo conventions, user-facing fixes should ship a changeset so the change appears in the release notes, e.g. "Allow safe file descriptor redirects (e.g. 2>&1) in read-only bash and clarify the source of permission denials".


Reply with @kilocode-bot fix it to have Kilo Code address this issue.

}) {
override get message() {
const rules = Array.isArray(this.ruleset) ? this.ruleset : [this.ruleset]
const source = rules.find((r) => r && typeof r === "object" && "source" in r)?.source

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[SUGGESTION]: Fork-merge hygiene on a shared file

packages/core/src/v1/permission.ts is shared upstream code, while the source marker on the ruleset ("agent" | "global" | "project" | ...) is Kilo-only, defined in packages/opencode/src/kilocode/permission/provenance.ts. Reading that Kilo-specific marker for the message wording enlarges the upstream diff. Consider wrapping the added block in // kilocode_change start / // kilocode_change end markers (or moving the wording into a Kilo-owned helper) so the next upstream merge resolves cleanly.


Reply with @kilocode-bot fix it to have Kilo Code address this issue.

@kilo-code-bot

kilo-code-bot Bot commented Sep 13, 2026

Copy link
Copy Markdown
Contributor

Code Review Summary

Status: 1 Issue Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 0
SUGGESTION 1
Issue Details (click to expand)

SUGGESTION

File Line Issue
packages/opencode/src/tool/shell.ts 152 No changeset for a user-visible behavior fix

Incremental review of abcb21d resolved the two prior blockers: the &>N / &>- bypass was removed from isSafeDescriptorRedirect, and the Kilo-specific denial-source logic in packages/core/src/v1/permission.ts is now wrapped in kilocode_change markers.

Files Reviewed (3 files)
  • packages/opencode/src/tool/shell.ts - 1 issue
  • packages/core/src/v1/permission.ts - 0 issues (fork-merge markers added)
  • packages/opencode/test/kilocode/permission/bash-redirect-permission.test.ts - 0 issues

Fix these issues in Kilo Cloud

Previous Review Summary (commit 6aae503)

Current summary above is authoritative. Previous snapshots are kept for context only.

Previous review (commit 6aae503)

Status: 3 Issues Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 1
SUGGESTION 2
Issue Details (click to expand)

WARNING

File Line Issue
packages/opencode/src/tool/shell.ts 136 &>N / &>- are file redirects, not descriptor duplications; stripping them from the pattern bypasses the *>* deny rule and read-only classification

SUGGESTION

File Line Issue
packages/opencode/src/tool/shell.ts 152 No changeset for a user-visible behavior fix
packages/core/src/v1/permission.ts 26 Kilo-specific source semantics added to a shared upstream file without fork-merge markers
Files Reviewed (3 files)
  • packages/opencode/src/tool/shell.ts - 2 issues
  • packages/core/src/v1/permission.ts - 1 issue
  • packages/opencode/test/kilocode/permission/bash-redirect-permission.test.ts - 0 issues

Fix these issues in Kilo Cloud


Reviewed by deepseek-v4.1-flash · Input: 0 · Output: 0 · Cached: 0

Review guidance: REVIEW.md from base branch main

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

plan agent: hardcoded bash permission ruleset denies safe commands with redirects (2>&1), unconfigurable via kilo.jsonc

1 participant