mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-19 04:07:28 +00:00
fix(node-host): sync rawCommand with hardened argv after executable path pinning
The security fix for GHSA-h3f9-mjwj-w476 added rawCommand/command[] consistency validation. After hardenApprovedExecutionPaths pins an executable to its absolute path (e.g. echo → /usr/bin/echo), the rawCommand was not updated, causing all nodes.run direct commands to fail validation. Regenerate rawCommand via formatExecCommand(hardening.argv) when hardening produces a new argv, so the consistency check passes. Closes #33080
This commit is contained in:
committed by
Gustavo Madeira Santana
parent
4fb40497d4
commit
fefb2fbe67
@@ -2,6 +2,7 @@ import fs from "node:fs";
|
|||||||
import os from "node:os";
|
import os from "node:os";
|
||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
import { describe, expect, it } from "vitest";
|
import { describe, expect, it } from "vitest";
|
||||||
|
import { formatExecCommand } from "../infra/system-run-command.js";
|
||||||
import {
|
import {
|
||||||
buildSystemRunApprovalPlan,
|
buildSystemRunApprovalPlan,
|
||||||
hardenApprovedExecutionPaths,
|
hardenApprovedExecutionPaths,
|
||||||
@@ -19,6 +20,7 @@ type HardeningCase = {
|
|||||||
withPathToken?: boolean;
|
withPathToken?: boolean;
|
||||||
expectedArgv: (ctx: { pathToken: PathTokenSetup | null }) => string[];
|
expectedArgv: (ctx: { pathToken: PathTokenSetup | null }) => string[];
|
||||||
expectedCmdText?: string;
|
expectedCmdText?: string;
|
||||||
|
checkRawCommandMatchesArgv?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
describe("hardenApprovedExecutionPaths", () => {
|
describe("hardenApprovedExecutionPaths", () => {
|
||||||
@@ -53,6 +55,14 @@ describe("hardenApprovedExecutionPaths", () => {
|
|||||||
withPathToken: true,
|
withPathToken: true,
|
||||||
expectedArgv: () => ["env", "poccmd", "SAFE"],
|
expectedArgv: () => ["env", "poccmd", "SAFE"],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "rawCommand matches hardened argv after executable path pinning",
|
||||||
|
mode: "build-plan",
|
||||||
|
argv: ["poccmd", "hello"],
|
||||||
|
withPathToken: true,
|
||||||
|
expectedArgv: ({ pathToken }) => [pathToken!.expected, "hello"],
|
||||||
|
checkRawCommandMatchesArgv: true,
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
for (const testCase of cases) {
|
for (const testCase of cases) {
|
||||||
@@ -82,6 +92,9 @@ describe("hardenApprovedExecutionPaths", () => {
|
|||||||
if (testCase.expectedCmdText) {
|
if (testCase.expectedCmdText) {
|
||||||
expect(prepared.cmdText).toBe(testCase.expectedCmdText);
|
expect(prepared.cmdText).toBe(testCase.expectedCmdText);
|
||||||
}
|
}
|
||||||
|
if (testCase.checkRawCommandMatchesArgv) {
|
||||||
|
expect(prepared.plan.rawCommand).toBe(formatExecCommand(prepared.plan.argv));
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import path from "node:path";
|
|||||||
import type { SystemRunApprovalPlan } from "../infra/exec-approvals.js";
|
import type { SystemRunApprovalPlan } from "../infra/exec-approvals.js";
|
||||||
import { resolveCommandResolutionFromArgv } from "../infra/exec-command-resolution.js";
|
import { resolveCommandResolutionFromArgv } from "../infra/exec-command-resolution.js";
|
||||||
import { sameFileIdentity } from "../infra/file-identity.js";
|
import { sameFileIdentity } from "../infra/file-identity.js";
|
||||||
import { resolveSystemRunCommand } from "../infra/system-run-command.js";
|
import { formatExecCommand, resolveSystemRunCommand } from "../infra/system-run-command.js";
|
||||||
|
|
||||||
export type ApprovedCwdSnapshot = {
|
export type ApprovedCwdSnapshot = {
|
||||||
cwd: string;
|
cwd: string;
|
||||||
@@ -239,12 +239,16 @@ export function buildSystemRunApprovalPlan(params: {
|
|||||||
if (!hardening.ok) {
|
if (!hardening.ok) {
|
||||||
return { ok: false, message: hardening.message };
|
return { ok: false, message: hardening.message };
|
||||||
}
|
}
|
||||||
|
const rawCommand =
|
||||||
|
hardening.argv === command.argv
|
||||||
|
? command.cmdText.trim() || null
|
||||||
|
: formatExecCommand(hardening.argv) || null;
|
||||||
return {
|
return {
|
||||||
ok: true,
|
ok: true,
|
||||||
plan: {
|
plan: {
|
||||||
argv: hardening.argv,
|
argv: hardening.argv,
|
||||||
cwd: hardening.cwd ?? null,
|
cwd: hardening.cwd ?? null,
|
||||||
rawCommand: command.cmdText.trim() || null,
|
rawCommand,
|
||||||
agentId: normalizeString(params.agentId),
|
agentId: normalizeString(params.agentId),
|
||||||
sessionKey: normalizeString(params.sessionKey),
|
sessionKey: normalizeString(params.sessionKey),
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user