fix(coding-agent): stop tool argument injection

closes #4018
This commit is contained in:
Mario Zechner
2026-04-30 21:31:43 +02:00
parent fe66edd943
commit 3d43d2e175
4 changed files with 29 additions and 2 deletions

View File

@@ -14,6 +14,7 @@
### Fixed
- Fixed `grep` and `find` tool argument injection for flag-like search patterns ([#4018](https://github.com/badlogic/pi-mono/issues/4018)).
- Updated `@mariozechner/clipboard` to an attested release so package managers with trust policies do not reject installs ([#3946](https://github.com/badlogic/pi-mono/issues/3946)).
- Fixed project context discovery to load `AGENTS.MD` files in addition to `AGENTS.md` ([#3949](https://github.com/badlogic/pi-mono/issues/3949)).
- Fixed `/handoff` to use compacted session context instead of pre-compaction raw messages ([#3945](https://github.com/badlogic/pi-mono/issues/3945)).

View File

@@ -246,7 +246,7 @@ export function createFindToolDefinition(
effectivePattern = `**/${pattern}`;
}
}
args.push(effectivePattern, searchPath);
args.push("--", effectivePattern, searchPath);
const child = spawn(fdPath, args, { stdio: ["ignore", "pipe", "pipe"] });
const rl = createInterface({ input: child.stdout });

View File

@@ -215,7 +215,7 @@ export function createGrepToolDefinition(
if (ignoreCase) args.push("--ignore-case");
if (literal) args.push("--fixed-strings");
if (glob) args.push("--glob", glob);
args.push(pattern, searchPath);
args.push("--", pattern, searchPath);
const child = spawn(rgPath, args, { stdio: ["ignore", "pipe", "pipe"] });
const rl = createInterface({ input: child.stdout });

View File

@@ -617,6 +617,23 @@ describe("Coding Agent Tools", () => {
// Ensure second match is not present
expect(output).not.toContain("match two");
});
it("should treat flag-like patterns as search text", async () => {
const marker = join(testDir, "grep-injection-marker");
const payload = join(testDir, "payload.sh");
const testFile = join(testDir, "target.txt");
writeFileSync(payload, `#!/bin/sh\necho executed > ${marker}\ncat "$1"\n`);
chmodSync(payload, 0o755);
writeFileSync(testFile, "target\n");
const result = await grepTool.execute("test-call-grep-injection", {
pattern: `--pre=${payload}`,
path: testDir,
});
expect(getTextOutput(result)).toContain("No matches found");
expect(existsSync(marker)).toBe(false);
});
});
describe("find tool", () => {
@@ -663,6 +680,15 @@ describe("Coding Agent Tools", () => {
}),
).rejects.toThrow(/error parsing glob|fd exited with code 1|fd error/i);
});
it("should treat flag-like patterns as search text", async () => {
const result = await findTool.execute("test-call-find-flag-pattern", {
pattern: "--help",
path: testDir,
});
expect(getTextOutput(result)).toContain("No files found matching pattern");
});
});
describe("ls tool", () => {