fix(exec): recognize PowerShell encoded commands

This commit is contained in:
Peter Steinberger
2026-03-07 23:15:37 +00:00
parent 5b27b0cecf
commit 1d1757b16f
4 changed files with 26 additions and 1 deletions

View File

@@ -300,6 +300,7 @@ Docs: https://docs.openclaw.ai
- Agents/model fallback visibility: warn when configured model IDs cannot be resolved and fallback is applied, with log-safe sanitization of model text to prevent control-sequence injection in warning output. (#39215) Thanks @ademczuk.
- Outbound delivery replay safety: use two-phase delivery ACK markers (`.json` -> `.delivered` -> unlink) and startup marker cleanup so crash windows between send and cleanup do not replay already-delivered messages. (#38668) Thanks @Gundam98.
- Nodes/system.run approval binding: carry prepared approval plans through gateway forwarding and bind interpreter-style script operands across approval to execution, so post-approval script rewrites are denied while unchanged approved script runs keep working. Thanks @tdjackey for reporting.
- Nodes/system.run PowerShell wrapper parsing: treat `pwsh`/`powershell` `-EncodedCommand` forms as shell-wrapper payloads so allowlist mode still requires approval instead of falling back to plain argv analysis. Thanks @tdjackey for reporting.
## 2026.3.2

View File

@@ -1,5 +1,12 @@
export const POSIX_INLINE_COMMAND_FLAGS = new Set(["-lc", "-c", "--command"]);
export const POWERSHELL_INLINE_COMMAND_FLAGS = new Set(["-c", "-command", "--command"]);
export const POWERSHELL_INLINE_COMMAND_FLAGS = new Set([
"-c",
"-command",
"--command",
"-encodedcommand",
"-enc",
"-e",
]);
export function resolveInlineCommandMatch(
argv: string[],

View File

@@ -59,6 +59,12 @@ describe("system run command helpers", () => {
test("extractShellCommandFromArgv supports fish and pwsh wrappers", () => {
expect(extractShellCommandFromArgv(["fish", "-c", "echo hi"])).toBe("echo hi");
expect(extractShellCommandFromArgv(["pwsh", "-Command", "Get-Date"])).toBe("Get-Date");
expect(extractShellCommandFromArgv(["pwsh", "-EncodedCommand", "ZQBjAGgAbwA="])).toBe(
"ZQBjAGgAbwA=",
);
expect(extractShellCommandFromArgv(["powershell", "-enc", "ZQBjAGgAbwA="])).toBe(
"ZQBjAGgAbwA=",
);
});
test("extractShellCommandFromArgv unwraps busybox/toybox shell applets", () => {

View File

@@ -847,6 +847,17 @@ describe("handleSystemRunInvoke mac app exec host routing", () => {
}
});
it("denies PowerShell encoded-command payloads in allowlist mode without explicit approval", async () => {
const { runCommand, sendInvokeResult, sendNodeEvent } = await runSystemInvoke({
preferMacAppExecHost: false,
security: "allowlist",
ask: "on-miss",
command: ["pwsh", "-EncodedCommand", "ZQBjAGgAbwAgAHAAdwBuAGUAZAA="],
});
expect(runCommand).not.toHaveBeenCalled();
expectApprovalRequiredDenied({ sendNodeEvent, sendInvokeResult });
});
it("denies nested env shell payloads when wrapper depth is exceeded", async () => {
if (process.platform === "win32") {
return;