mirror of
https://github.com/moltbot/moltbot.git
synced 2026-03-09 15:35:17 +00:00
fix: block safeBins sort --compress-program bypass
This commit is contained in:
@@ -32,6 +32,7 @@ Docs: https://docs.openclaw.ai
|
||||
|
||||
### Fixes
|
||||
|
||||
- Security/Exec: block `sort --compress-program` in `tools.exec.safeBins` policy so allowlist-mode safe-bin checks cannot be used to bypass approval and spawn external programs. Thanks @tdjackey for reporting.
|
||||
- Doctor/State integrity: only require/create the OAuth credentials directory when WhatsApp or pairing-backed channels are configured, and downgrade fresh-install missing-dir noise to an informational warning.
|
||||
- Security/Agents: cap embedded Pi runner outer retry loop with a higher profile-aware dynamic limit (32-160 attempts) and return an explicit `retry_limit` error payload when retries never converge, preventing unbounded internal retry cycles (`GHSA-76m6-pj3w-v7mf`).
|
||||
- Telegram: detect duplicate bot-token ownership across Telegram accounts at startup/status time, mark secondary accounts as not configured with an explicit fix message, and block duplicate account startup before polling to avoid endless `getUpdates` conflict loops.
|
||||
|
||||
@@ -127,9 +127,10 @@ positional file args and path-like tokens, so they can only operate on the incom
|
||||
Validation is deterministic from argv shape only (no host filesystem existence checks), which
|
||||
prevents file-existence oracle behavior from allow/deny differences.
|
||||
File-oriented options are denied for default safe bins (for example `sort -o`, `sort --output`,
|
||||
`sort --files0-from`, `wc --files0-from`, `jq -f/--from-file`, `grep -f/--file`).
|
||||
`sort --files0-from`, `sort --compress-program`, `wc --files0-from`, `jq -f/--from-file`,
|
||||
`grep -f/--file`).
|
||||
Safe bins also enforce explicit per-binary flag policy for options that break stdin-only
|
||||
behavior (for example `sort -o/--output` and grep recursive flags).
|
||||
behavior (for example `sort -o/--output/--compress-program` and grep recursive flags).
|
||||
Safe bins also force argv tokens to be treated as **literal text** at execution time (no globbing
|
||||
and no `$VARS` expansion) for stdin-only segments, so patterns like `*` or `$HOME/...` cannot be
|
||||
used to smuggle file reads.
|
||||
|
||||
@@ -222,6 +222,24 @@ describe("createOpenClawCodingTools safeBins", () => {
|
||||
}
|
||||
});
|
||||
|
||||
it("blocks sort --compress-program from bypassing safeBins", async () => {
|
||||
if (process.platform === "win32") {
|
||||
return;
|
||||
}
|
||||
|
||||
const { tmpDir, execTool } = await createSafeBinsExecTool({
|
||||
tmpPrefix: "openclaw-safe-bins-sort-compress-",
|
||||
safeBins: ["sort"],
|
||||
});
|
||||
|
||||
await expect(
|
||||
execTool.execute("call1", {
|
||||
command: "sort --compress-program=sh",
|
||||
workdir: tmpDir,
|
||||
}),
|
||||
).rejects.toThrow("exec denied: allowlist miss");
|
||||
});
|
||||
|
||||
it("blocks shell redirection metacharacters in safeBins mode", async () => {
|
||||
if (process.platform === "win32") {
|
||||
return;
|
||||
|
||||
@@ -564,6 +564,22 @@ describe("exec approvals safe bins", () => {
|
||||
safeBins: ["sort"],
|
||||
executableName: "sort",
|
||||
},
|
||||
{
|
||||
name: "blocks sort external program flag via --compress-program=<prog>",
|
||||
argv: ["sort", "--compress-program=sh"],
|
||||
resolvedPath: "/usr/bin/sort",
|
||||
expected: false,
|
||||
safeBins: ["sort"],
|
||||
executableName: "sort",
|
||||
},
|
||||
{
|
||||
name: "blocks sort external program flag via --compress-program <prog>",
|
||||
argv: ["sort", "--compress-program", "sh"],
|
||||
resolvedPath: "/usr/bin/sort",
|
||||
expected: false,
|
||||
safeBins: ["sort"],
|
||||
executableName: "sort",
|
||||
},
|
||||
{
|
||||
name: "blocks grep recursive flags that read cwd",
|
||||
argv: ["grep", "-R", "needle"],
|
||||
|
||||
@@ -20,3 +20,17 @@ describe("exec safe bin policy grep", () => {
|
||||
expect(validateSafeBinArgv(["-e", "KEY", "--", ".env"], grepProfile)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("exec safe bin policy sort", () => {
|
||||
const sortProfile = SAFE_BIN_PROFILES.sort;
|
||||
|
||||
it("allows stdin-only sort flags", () => {
|
||||
expect(validateSafeBinArgv(["-S", "1M"], sortProfile)).toBe(true);
|
||||
expect(validateSafeBinArgv(["--key=1,1"], sortProfile)).toBe(true);
|
||||
});
|
||||
|
||||
it("blocks sort --compress-program in safe-bin mode", () => {
|
||||
expect(validateSafeBinArgv(["--compress-program=sh"], sortProfile)).toBe(false);
|
||||
expect(validateSafeBinArgv(["--compress-program", "sh"], sortProfile)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -151,7 +151,6 @@ export const SAFE_BIN_PROFILE_FIXTURES: Record<string, SafeBinProfileFixture> =
|
||||
"--field-separator",
|
||||
"--buffer-size",
|
||||
"--temporary-directory",
|
||||
"--compress-program",
|
||||
"--parallel",
|
||||
"--batch-size",
|
||||
"--random-source",
|
||||
@@ -163,7 +162,8 @@ export const SAFE_BIN_PROFILE_FIXTURES: Record<string, SafeBinProfileFixture> =
|
||||
"-T",
|
||||
"-o",
|
||||
],
|
||||
blockedFlags: ["--files0-from", "--output", "-o"],
|
||||
// --compress-program can invoke an external executable and breaks stdin-only guarantees.
|
||||
blockedFlags: ["--compress-program", "--files0-from", "--output", "-o"],
|
||||
},
|
||||
uniq: {
|
||||
maxPositional: 0,
|
||||
|
||||
Reference in New Issue
Block a user