Files
OmniRoute/tests/unit/acp-registry.test.ts
Diego Rodrigues de Sa e Souza 60829241fd fix(security): close 4 STILL-REAL advisory findings (ACP RCE hardening, db-backups tier, uppercase authz bypass, spawn-veto drift) (#11028)
5 — 4 achados STILL-REAL de advisories de segurança, cada um com TDD (RED→GREEN) e crédito ao reporter original: ACP RCE hardening (resolveVersionProbe), db-backups Tier-2 allowlist, uppercase authz bypass (matcher case-insensitive), spawn-veto drift (chatgpt-web-codex-doctor). typecheck/lint limpos, suíte authz/acp/cors verde. UNSTABLE é o base-red inherited #9985, já documentado no corpo da PR.
2026-08-21 13:57:42 -03:00

87 lines
3.4 KiB
TypeScript

import test from "node:test";
import assert from "node:assert/strict";
const { resolveVersionProbe, shouldUseShellForVersionProbe } =
await import("../../src/lib/acp/registry.ts");
const { getAgentById } = await import("../../src/lib/acp/registry.ts");
test("resolveVersionProbe parses quoted binary paths without shell semantics", () => {
const probe = resolveVersionProbe(
"/tmp/My Custom Agent",
'"/tmp/My Custom Agent" --version',
true
);
assert.deepEqual(probe, {
command: "/tmp/My Custom Agent",
args: ["--version"],
});
});
test("resolveVersionProbe rejects custom version commands that switch binaries", () => {
const probe = resolveVersionProbe("/tmp/custom-agent", 'bash -lc "id"', true);
assert.equal(probe, null);
});
test("resolveVersionProbe rejects shell metacharacters in version commands", () => {
const probe = resolveVersionProbe(
"/tmp/custom-agent",
"/tmp/custom-agent --version; touch /tmp/pwned",
true
);
assert.equal(probe, null);
});
// Regression guard — GHSA-jphr-2gw7-xrwp / GHSA-hf57-cqmx-p4gr (ACP custom-agent
// RCE). A client-registered custom agent controls both `binary` and
// `versionCommand`; the binary-match check alone still admits an eval-style
// argument on a matching interpreter, which reaches execFileSync as arbitrary
// code execution (no shell metacharacter required). A version *probe* only ever
// needs a version flag, so untrusted probes must reject non-version arguments.
test("resolveVersionProbe rejects interpreter eval arguments on a matching binary", () => {
assert.equal(resolveVersionProbe("node", 'node -e "process.exit(1)"', true), null);
assert.equal(resolveVersionProbe("node", "node --eval 1", true), null);
assert.equal(resolveVersionProbe("python3", 'python3 -c "import os"', true), null);
assert.equal(resolveVersionProbe("ruby", 'ruby -e "puts 1"', true), null);
// Any extra argument beyond a single version flag is refused for a probe.
assert.equal(resolveVersionProbe("node", "node --version --eval 1", true), null);
});
test("resolveVersionProbe still accepts legitimate version flags for custom agents", () => {
assert.deepEqual(resolveVersionProbe("node", "node --version", true), {
command: "node",
args: ["--version"],
});
assert.deepEqual(resolveVersionProbe("my-agent", "my-agent -v", true), {
command: "my-agent",
args: ["-v"],
});
assert.deepEqual(resolveVersionProbe("my-agent", "my-agent version", true), {
command: "my-agent",
args: ["version"],
});
// Bare binary with no arguments is a valid probe too.
assert.deepEqual(resolveVersionProbe("my-agent", "my-agent", true), {
command: "my-agent",
args: [],
});
});
test("shouldUseShellForVersionProbe preserves Windows npm wrapper detection", () => {
assert.equal(shouldUseShellForVersionProbe("codex", "win32"), true);
assert.equal(
shouldUseShellForVersionProbe("C:\\Users\\dev\\AppData\\Roaming\\npm\\codex.cmd", "win32"),
true
);
assert.equal(shouldUseShellForVersionProbe("C:\\Tools\\claude.exe", "win32"), false);
assert.equal(shouldUseShellForVersionProbe("codex", "linux"), false);
});
test("Qwen Code is registered with its upstream ACP mode", () => {
const qwen = getAgentById("qwen");
assert.ok(qwen);
assert.deepEqual(qwen.spawnArgs, ["--acp"]);
assert.equal(qwen.providerAlias, "qwen-code");
assert.equal(qwen.protocol, "stdio");
});