mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 07:30:43 +00:00
fix(exec): detect combined env split carriers
This commit is contained in:
@@ -50,6 +50,7 @@ Docs: https://docs.openclaw.ai
|
||||
|
||||
### Fixes
|
||||
|
||||
- Exec approvals: detect `env -S` split-string command-carrier risks when `-S`/`-s` is combined with other env short options, so approval explanations do not miss split payloads hidden behind `env -iS...`. Thanks @vincentkoc.
|
||||
- Voice Call: mark realtime calls completed when the realtime provider closes normally, so Twilio/OpenAI/Google realtime stop events do not leave active call records behind. Thanks @vincentkoc.
|
||||
- Exec approvals: treat POSIX `exec` as a command carrier for inline eval, shell-wrapper, and eval/source detection, so approval explanations and command-risk checks do not miss payloads hidden behind `exec`. Thanks @vincentkoc.
|
||||
- Google Meet: log the resolved audio provider model when starting Chrome and paired-node Meet talk-back bridges, so agent-mode joins show the STT model and bidi joins show the realtime voice model.
|
||||
|
||||
@@ -91,8 +91,12 @@ describe("command-analysis risks", () => {
|
||||
it("detects env split-string flag forms", () => {
|
||||
expect(detectEnvSplitStringFlag(["env", "-S", "sh -c id"])).toBe("-S");
|
||||
expect(detectEnvSplitStringFlag(["env", "-Ssh -c id"])).toBe("-S");
|
||||
expect(detectEnvSplitStringFlag(["env", "-iS", "sh -c id"])).toBe("-S");
|
||||
expect(detectEnvSplitStringFlag(["env", "-iSsh -c id"])).toBe("-S");
|
||||
expect(detectEnvSplitStringFlag(["env", "-is", "sh -c id"])).toBe("-s");
|
||||
expect(detectEnvSplitStringFlag(["env", "--split-string=sh -c id"])).toBe("--split-string");
|
||||
expect(detectEnvSplitStringFlag(["env", "sh", "-c", "id"])).toBeNull();
|
||||
expect(detectEnvSplitStringFlag(["env", "-XSsh -c id"])).toBeNull();
|
||||
});
|
||||
|
||||
it("detects shell wrappers carried through prefix commands", () => {
|
||||
|
||||
@@ -2,6 +2,7 @@ import { splitShellArgs } from "../../utils/shell-argv.js";
|
||||
import {
|
||||
COMMAND_CARRIER_EXECUTABLES,
|
||||
isEnvAssignmentToken,
|
||||
parseEnvInvocationPrelude,
|
||||
resolveCarrierCommandArgv,
|
||||
SOURCE_EXECUTABLES,
|
||||
} from "../command-carriers.js";
|
||||
@@ -169,14 +170,31 @@ export function detectEnvSplitStringFlag(argv: string[]): string | null {
|
||||
if (normalizeExecutableToken(argv[0] ?? "") !== "env") {
|
||||
return null;
|
||||
}
|
||||
for (const arg of argv.slice(1)) {
|
||||
const parsed = parseEnvInvocationPrelude(argv);
|
||||
if (!parsed?.splitArgv) {
|
||||
return null;
|
||||
}
|
||||
for (const arg of argv.slice(1, parsed.commandIndex)) {
|
||||
const token = arg.trim();
|
||||
if (token === "-S" || token === "--split-string") {
|
||||
if (token === "-S" || token === "-s") {
|
||||
return token;
|
||||
}
|
||||
if (token === "--split-string") {
|
||||
return "--split-string";
|
||||
}
|
||||
if (token.startsWith("--split-string=") || (token.startsWith("-S") && token.length > 2)) {
|
||||
return token.startsWith("--") ? "--split-string" : "-S";
|
||||
}
|
||||
if (token.startsWith("-") && !token.startsWith("--")) {
|
||||
for (const option of token.slice(1)) {
|
||||
if (option === "S") {
|
||||
return "-S";
|
||||
}
|
||||
if (option === "s") {
|
||||
return "-s";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -602,6 +602,10 @@ describe("command explainer tree-sitter runtime", () => {
|
||||
expect(envSplitString.risks).toContainEqual(
|
||||
expect.objectContaining({ kind: "command-carrier", command: "env", flag: "-S" }),
|
||||
);
|
||||
const envCombinedSplitString = await explainShellCommand("env -iS 'sh -c \"id\"'");
|
||||
expect(envCombinedSplitString.risks).toContainEqual(
|
||||
expect.objectContaining({ kind: "command-carrier", command: "env", flag: "-S" }),
|
||||
);
|
||||
|
||||
for (const command of [
|
||||
'env python -c "print(1)"',
|
||||
|
||||
Reference in New Issue
Block a user