core: restore bash command security validation to prevent accidental directory traversal

The permission validation that prevents commands from accessing paths outside the project directory was accidentally disabled, which could allow commands like 'cd ../' to escape the workspace. This restores the security check that keeps your commands safely contained within your project boundaries.
This commit is contained in:
Dax Raad
2025-10-06 23:24:07 -04:00
parent 10998d62b9
commit 2bf0e42367
2 changed files with 12 additions and 14 deletions

View File

@@ -3,17 +3,22 @@ import { exec } from "child_process"
import { Tool } from "./tool" import { Tool } from "./tool"
import DESCRIPTION from "./bash.txt" import DESCRIPTION from "./bash.txt"
import { Permission } from "../permission"
import { Filesystem } from "../util/filesystem"
import { lazy } from "../util/lazy" import { lazy } from "../util/lazy"
import { Log } from "../util/log" import { Log } from "../util/log"
import { Wildcard } from "../util/wildcard"
import { $ } from "bun"
import { Instance } from "../project/instance" import { Instance } from "../project/instance"
import { Agent } from "../agent/agent"
const MAX_OUTPUT_LENGTH = 30_000 const MAX_OUTPUT_LENGTH = 30_000
const DEFAULT_TIMEOUT = 1 * 60 * 1000 const DEFAULT_TIMEOUT = 1 * 60 * 1000
const MAX_TIMEOUT = 10 * 60 * 1000 const MAX_TIMEOUT = 10 * 60 * 1000
export const log = Log.create({ service: "bash-tool" }) const log = Log.create({ service: "bash-tool" })
export const parser = lazy(async () => { const parser = lazy(async () => {
try { try {
const { default: Parser } = await import("tree-sitter") const { default: Parser } = await import("tree-sitter")
const Bash = await import("tree-sitter-bash") const Bash = await import("tree-sitter-bash")
@@ -21,10 +26,8 @@ export const parser = lazy(async () => {
p.setLanguage(Bash.language as any) p.setLanguage(Bash.language as any)
return p return p
} catch (e) { } catch (e) {
const { Parser, Language } = await import("web-tree-sitter") const { default: Parser } = await import("web-tree-sitter")
const { default: treeWasm } = await import("web-tree-sitter/web-tree-sitter.wasm" as string, { const { default: treeWasm } = await import("web-tree-sitter/tree-sitter.wasm" as string, { with: { type: "wasm" } })
with: { type: "wasm" },
})
await Parser.init({ await Parser.init({
locateFile() { locateFile() {
return treeWasm return treeWasm
@@ -33,7 +36,7 @@ export const parser = lazy(async () => {
const { default: bashWasm } = await import("tree-sitter-bash/tree-sitter-bash.wasm" as string, { const { default: bashWasm } = await import("tree-sitter-bash/tree-sitter-bash.wasm" as string, {
with: { type: "wasm" }, with: { type: "wasm" },
}) })
const bashLanguage = await Language.load(bashWasm) const bashLanguage = await Parser.Language.load(bashWasm)
const p = new Parser() const p = new Parser()
p.setLanguage(bashLanguage) p.setLanguage(bashLanguage)
return p return p
@@ -53,11 +56,7 @@ export const BashTool = Tool.define("bash", {
}), }),
async execute(params, ctx) { async execute(params, ctx) {
const timeout = Math.min(params.timeout ?? DEFAULT_TIMEOUT, MAX_TIMEOUT) const timeout = Math.min(params.timeout ?? DEFAULT_TIMEOUT, MAX_TIMEOUT)
/*
const tree = await parser().then((p) => p.parse(params.command)) const tree = await parser().then((p) => p.parse(params.command))
if (!tree) {
throw new Error("Failed to parse command")
}
const permissions = await Agent.get(ctx.agent).then((x) => x.permission.bash) const permissions = await Agent.get(ctx.agent).then((x) => x.permission.bash)
const askPatterns = new Set<string>() const askPatterns = new Set<string>()
@@ -146,7 +145,6 @@ export const BashTool = Tool.define("bash", {
}, },
}) })
} }
*/
const process = exec(params.command, { const process = exec(params.command, {
cwd: Instance.directory, cwd: Instance.directory,

View File

@@ -6,7 +6,7 @@ const parser = async () => {
p.setLanguage(Bash.language as any) p.setLanguage(Bash.language as any)
return p return p
} catch (e) { } catch (e) {
const { Parser, Language } = await import("web-tree-sitter") const { default: Parser } = await import("web-tree-sitter")
const { default: treeWasm } = await import("web-tree-sitter/web-tree-sitter.wasm" as string, { const { default: treeWasm } = await import("web-tree-sitter/web-tree-sitter.wasm" as string, {
with: { type: "wasm" }, with: { type: "wasm" },
}) })
@@ -18,7 +18,7 @@ const parser = async () => {
const { default: bashWasm } = await import("tree-sitter-bash/tree-sitter-bash.wasm" as string, { const { default: bashWasm } = await import("tree-sitter-bash/tree-sitter-bash.wasm" as string, {
with: { type: "wasm" }, with: { type: "wasm" },
}) })
const bashLanguage = await Language.load(bashWasm) const bashLanguage = await Parser.Language.load(bashWasm)
const p = new Parser() const p = new Parser()
p.setLanguage(bashLanguage) p.setLanguage(bashLanguage)
return p return p