fix: preserve strict inline-eval approval boundaries (#59780) (thanks @luoyanglang)

This commit is contained in:
Peter Steinberger
2026-04-02 18:24:20 +01:00
parent f03d7c5a4c
commit 3e452f2671
5 changed files with 91 additions and 40 deletions

View File

@@ -1320,6 +1320,36 @@ describe("handleSystemRunInvoke mac app exec host routing", () => {
}
});
it("prefers strict inline-eval denial over generic allowlist prompts", async () => {
setRuntimeConfigSnapshot({
tools: {
exec: {
strictInlineEval: true,
},
},
});
try {
const { runCommand, sendInvokeResult, sendNodeEvent } = await runSystemInvoke({
preferMacAppExecHost: false,
command: ["awk", 'BEGIN{system("id")}', "/dev/null"],
security: "allowlist",
ask: "on-miss",
});
expect(runCommand).not.toHaveBeenCalled();
expect(sendNodeEvent).toHaveBeenCalledWith(
expect.anything(),
"exec.denied",
expect.objectContaining({ reason: "approval-required" }),
);
expectInvokeErrorMessage(sendInvokeResult, {
message: "awk inline program requires explicit approval in strictInlineEval mode",
});
} finally {
clearRuntimeConfigSnapshot();
}
});
it.each([
{ executable: "python3", args: ["-c", "print('hi')"] },
{ executable: "awk", args: ['BEGIN{system("id")}', "/dev/null"] },

View File

@@ -384,15 +384,11 @@ async function evaluateSystemRunPolicyPhase(
});
analysisOk = policy.analysisOk;
allowlistSatisfied = policy.allowlistSatisfied;
if (!policy.allowed) {
await sendSystemRunDenied(opts, parsed.execution, {
reason: policy.eventReason,
message: policy.errorMessage,
});
return null;
}
if (inlineEvalHit && !policy.approvedByAsk) {
const strictInlineEvalRequiresApproval =
inlineEvalHit !== null &&
!policy.approvedByAsk &&
(policy.allowed ? true : policy.eventReason !== "security=deny");
if (strictInlineEvalRequiresApproval) {
await sendSystemRunDenied(opts, parsed.execution, {
reason: "approval-required",
message:
@@ -402,6 +398,14 @@ async function evaluateSystemRunPolicyPhase(
return null;
}
if (!policy.allowed) {
await sendSystemRunDenied(opts, parsed.execution, {
reason: policy.eventReason,
message: policy.errorMessage,
});
return null;
}
// Fail closed if policy/runtime drift re-allows unapproved shell wrappers.
if (
security === "allowlist" &&