OpenBMB / OpenBMB/PilotDeck

bug(plan-mode): bash read-only classifier allows redirection writes

Open
#258 0 comments 0 reactions 1 assignee View on GitHub

@Kaguya-19 is already working on this.

Since Jun 24, 2026.

Dominant language
TypeScript
Stars
4k
Forks
453
Avg merge
12h 30m
Merged PRs (30d)
46

Description

Summary

Plan mode treats some bash commands as read-only by prefix match only. Commands such as echo, printf, and node -e are classified as read-only even when they contain shell redirection or obvious file-writing JavaScript, so Plan mode can be bypassed to write arbitrary files.

Why it matters

Plan mode promises a constrained, read-only exploration phase, with writes limited to plan markdown files under .pilotdeck/plans/. The tool schema tells the model that bash is available for read-only commands. If echo SIDE_EFFECT > file, printf ... >> file, or node -e "fs.writeFileSync(...)" is allowed, Plan mode no longer enforces that boundary.

Evidence

  • src/tool/planModeConstraints.ts:11 to src/tool/planModeConstraints.ts:26 includes bash in the Plan mode allowed tool set.
  • src/tool/planModeConstraints.ts:32 to src/tool/planModeConstraints.ts:35 describes Plan mode bash as read-only.
  • src/tool/execution/ToolRuntime.ts:48 to src/tool/execution/ToolRuntime.ts:57 blocks tools not in the Plan mode allowlist; bash passes this gate.
  • src/tool/builtin/bash/permissions.ts:35 to src/tool/builtin/bash/permissions.ts:45 marks printf, echo, and node -e as safe read patterns by prefix.
  • src/tool/builtin/bash/permissions.ts:95 to src/tool/builtin/bash/permissions.ts:97 implements isReadOnlyShellCommand as “any safe pattern matches.”
  • src/tool/builtin/bash.ts:59 to src/tool/builtin/bash.ts:60 exposes that classifier as the bash tool’s isReadOnly.
  • src/permission/decision/PermissionRuntime.ts:94 to src/permission/decision/PermissionRuntime.ts:99 allows read-only tools in Plan mode even when the tool permission would otherwise ask.
  • src/permission/decision/PermissionRuntime.ts:184 to src/permission/decision/PermissionRuntime.ts:185 allows Plan mode when tool.isReadOnly(input) is true.
  • src/permission/decision/PermissionRuntime.ts:373 to src/permission/decision/PermissionRuntime.ts:377 builds the Plan mode bash deny message only on the non-read-only path.
  • src/tool/builtin/bash.ts:86 to src/tool/builtin/bash.ts:93 passes the command to the shell runner.
  • src/tool/builtin/bash/commandRunner.ts:30 to src/tool/builtin/bash/commandRunner.ts:34 runs commands with shell: true, so shell redirection is effective.

Validation

Validation level: dynamic permission/runtime reproduction.

Repro approach: evaluate echo SIDE_EFFECT > plan-mode-write.txt through the bash read-only classifier and Plan mode permission runtime, then execute the bash command.

Key output: isReadOnlyShellCommand classified the command as read-only, PermissionRuntime returned allow in Plan mode, and shell execution created the file.

Boundary: this did not require a full agent loop. The permission runtime and bash tool are the same core path used by agent tool execution.

Expected behavior

Plan mode should reject bash commands that can write or mutate files, even if they start with a command that is sometimes read-only. Redirection, append redirection, shell command composition, and obvious file-writing node -e scripts should not be allowed under the read-only classifier.

Existing coverage checked

Coverage review checked existing Plan mode hardening work.

Coverage label: partially covered. Merged PR #216 and PR #220 strengthen Plan mode enforcement, tool filtering, error formatting, and UI presentation. They cover adjacent Plan mode hardening, but not this root cause: the bash read-only classifier still allows write-capable commands such as echo > file.

Suggested fix

Make the shell read-only classifier conservative. Reject commands containing redirection operators, write-oriented pipes, command separators that compose writes, and node -e snippets containing obvious filesystem write APIs. Alternatively, use a stricter Plan mode bash allowlist that only permits known read-only commands without shell metacharacters.

Suggested tests

  • echo SIDE_EFFECT > file is rejected.
  • printf SIDE_EFFECT >> file is rejected.
  • node -e "fs.writeFileSync('file','x')" is rejected.
  • Command chaining that writes after a read-looking prefix is rejected.
  • Known read-only commands such as pwd, ls, and git status still pass.

Submitted with Codex.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.