fix(security): harden node exec approvals against symlink rebind

This commit is contained in:
Peter Steinberger
2026-02-26 21:47:38 +01:00
parent 611dff985d
commit 78a7ff2d50
15 changed files with 489 additions and 43 deletions

View File

@@ -20,12 +20,22 @@ export type SystemRunApprovalBindingV1 = {
envHash: string | null;
};
export type SystemRunApprovalPlanV2 = {
version: 2;
argv: string[];
cwd: string | null;
rawCommand: string | null;
agentId: string | null;
sessionKey: string | null;
};
export type ExecApprovalRequestPayload = {
command: string;
commandArgv?: string[];
// Optional UI-safe env key preview for approval prompts.
envKeys?: string[];
systemRunBindingV1?: SystemRunApprovalBindingV1 | null;
systemRunPlanV2?: SystemRunApprovalPlanV2 | null;
cwd?: string | null;
nodeId?: string | null;
host?: string | null;

View File

@@ -1,5 +1,5 @@
import crypto from "node:crypto";
import type { SystemRunApprovalBindingV1 } from "./exec-approvals.js";
import type { SystemRunApprovalBindingV1, SystemRunApprovalPlanV2 } from "./exec-approvals.js";
import { normalizeEnvVarKey } from "./host-env-security.js";
type NormalizedSystemRunEnvEntry = [key: string, value: string];
@@ -16,6 +16,28 @@ function normalizeStringArray(value: unknown): string[] {
return Array.isArray(value) ? value.map((entry) => String(entry)) : [];
}
export function normalizeSystemRunApprovalPlanV2(value: unknown): SystemRunApprovalPlanV2 | null {
if (!value || typeof value !== "object" || Array.isArray(value)) {
return null;
}
const candidate = value as Record<string, unknown>;
if (candidate.version !== 2) {
return null;
}
const argv = normalizeStringArray(candidate.argv);
if (argv.length === 0) {
return null;
}
return {
version: 2,
argv,
cwd: normalizeString(candidate.cwd),
rawCommand: normalizeString(candidate.rawCommand),
agentId: normalizeString(candidate.agentId),
sessionKey: normalizeString(candidate.sessionKey),
};
}
function normalizeSystemRunEnvEntries(env: unknown): NormalizedSystemRunEnvEntry[] {
if (!env || typeof env !== "object" || Array.isArray(env)) {
return [];