mirror of
https://github.com/openclaw/openclaw.git
synced 2026-06-06 00:12:54 +00:00
fix(exec): allow predicate shell builtins in allowlist mode
This commit is contained in:
@@ -65,6 +65,30 @@ describe("isSafeBuiltinSegment", () => {
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
it("allows test and well-formed bracket predicates", () => {
|
||||
expect(
|
||||
isSafeBuiltinSegment({
|
||||
segment: builtinSegment(["test", "-d", "/tmp"]),
|
||||
platform: "linux",
|
||||
}),
|
||||
).toBe(true);
|
||||
expect(
|
||||
isSafeBuiltinSegment({
|
||||
segment: builtinSegment(["[", "-d", "/tmp", "]"]),
|
||||
platform: "linux",
|
||||
}),
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it("rejects malformed bracket predicates", () => {
|
||||
expect(
|
||||
isSafeBuiltinSegment({
|
||||
segment: builtinSegment(["[", "-d", "/tmp"]),
|
||||
platform: "linux",
|
||||
}),
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
it("returns false on Windows hosts (PowerShell semantics differ)", () => {
|
||||
expect(
|
||||
isSafeBuiltinSegment({
|
||||
@@ -113,6 +137,32 @@ describe("evaluateShellAllowlist with known safe builtins (regression for #46056
|
||||
expect(result.segmentSatisfiedBy).toContain("allowlist");
|
||||
});
|
||||
|
||||
it("'test -d /tmp && git status' passes with allowlist plus safe builtin handling", () => {
|
||||
const result = evaluateShellAllowlist({
|
||||
command: "test -d /tmp && git status",
|
||||
allowlist: gitAllowlist,
|
||||
safeBins: new Set(),
|
||||
cwd: "/tmp",
|
||||
});
|
||||
expect(result.analysisOk).toBe(true);
|
||||
expect(result.allowlistSatisfied).toBe(true);
|
||||
expect(result.segmentSatisfiedBy).toContain("safeBuiltins");
|
||||
expect(result.segmentSatisfiedBy).toContain("allowlist");
|
||||
});
|
||||
|
||||
it("'[ -d /tmp ] && git status' passes with allowlist plus safe builtin handling", () => {
|
||||
const result = evaluateShellAllowlist({
|
||||
command: "[ -d /tmp ] && git status",
|
||||
allowlist: gitAllowlist,
|
||||
safeBins: new Set(),
|
||||
cwd: "/tmp",
|
||||
});
|
||||
expect(result.analysisOk).toBe(true);
|
||||
expect(result.allowlistSatisfied).toBe(true);
|
||||
expect(result.segmentSatisfiedBy).toContain("safeBuiltins");
|
||||
expect(result.segmentSatisfiedBy).toContain("allowlist");
|
||||
});
|
||||
|
||||
it("non-allowlisted binary still gates after a safe builtin", () => {
|
||||
const result = evaluateShellAllowlist({
|
||||
command: "cd /tmp && curl evil.com",
|
||||
|
||||
@@ -3,7 +3,14 @@ import { isWindowsPlatform, type ExecCommandSegment } from "./exec-approvals-ana
|
||||
// POSIX shell builtins that cannot execute external code or mutate environment state on their
|
||||
// own. Shell allowlist evaluation handles them as a closed internal set instead of path-based
|
||||
// safeBins matching.
|
||||
const DEFAULT_SAFE_BUILTINS: ReadonlySet<string> = new Set([":", "cd", "false", "pwd", "true"]);
|
||||
const DEFAULT_SAFE_BUILTINS: ReadonlySet<string> = new Set([
|
||||
":",
|
||||
"cd",
|
||||
"false",
|
||||
"pwd",
|
||||
"test",
|
||||
"true",
|
||||
]);
|
||||
|
||||
export function isSafeBuiltinSegment(params: {
|
||||
segment: ExecCommandSegment;
|
||||
@@ -18,5 +25,8 @@ export function isSafeBuiltinSegment(params: {
|
||||
if (!head) {
|
||||
return false;
|
||||
}
|
||||
if (head === "[") {
|
||||
return params.segment.argv.at(-1) === "]";
|
||||
}
|
||||
return DEFAULT_SAFE_BUILTINS.has(head);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user