fix(security): harden exec wrapper allowlist execution parity

This commit is contained in:
Peter Steinberger
2026-02-24 01:51:33 +00:00
parent 5eb72ab769
commit a1c4bf07c6
12 changed files with 289 additions and 65 deletions

View File

@@ -626,12 +626,30 @@ function renderQuotedArgv(argv: string[]): string {
return argv.map((token) => shellEscapeSingleArg(token)).join(" ");
}
function renderSafeBinSegmentArgv(segment: ExecCommandSegment): string {
if (segment.argv.length === 0) {
return "";
function resolvePlannedSegmentArgv(segment: ExecCommandSegment): string[] | null {
if (segment.resolution?.policyBlocked === true) {
return null;
}
const baseArgv =
segment.resolution?.effectiveArgv && segment.resolution.effectiveArgv.length > 0
? segment.resolution.effectiveArgv
: segment.argv;
if (baseArgv.length === 0) {
return null;
}
const argv = [...baseArgv];
const resolvedExecutable = segment.resolution?.resolvedPath?.trim() ?? "";
if (resolvedExecutable) {
argv[0] = resolvedExecutable;
}
return argv;
}
function renderSafeBinSegmentArgv(segment: ExecCommandSegment): string | null {
const argv = resolvePlannedSegmentArgv(segment);
if (!argv || argv.length === 0) {
return null;
}
const resolvedExecutable = segment.resolution?.resolvedPath?.trim();
const argv = resolvedExecutable ? [resolvedExecutable, ...segment.argv.slice(1)] : segment.argv;
return renderQuotedArgv(argv);
}
@@ -659,7 +677,43 @@ export function buildSafeBinsShellCommand(params: {
return { ok: false, reason: "segment mapping failed" };
}
const needsLiteral = by === "safeBins";
return { ok: true, rendered: needsLiteral ? renderSafeBinSegmentArgv(seg) : raw.trim() };
if (!needsLiteral) {
return { ok: true, rendered: raw.trim() };
}
const rendered = renderSafeBinSegmentArgv(seg);
if (!rendered) {
return { ok: false, reason: "segment execution plan unavailable" };
}
return { ok: true, rendered };
},
});
if (!rebuilt.ok) {
return { ok: false, reason: rebuilt.reason };
}
if (rebuilt.segmentCount !== params.segments.length) {
return { ok: false, reason: "segment count mismatch" };
}
return { ok: true, command: rebuilt.command };
}
export function buildEnforcedShellCommand(params: {
command: string;
segments: ExecCommandSegment[];
platform?: string | null;
}): { ok: boolean; command?: string; reason?: string } {
const rebuilt = rebuildShellCommandFromSource({
command: params.command,
platform: params.platform,
renderSegment: (_raw, segmentIndex) => {
const seg = params.segments[segmentIndex];
if (!seg) {
return { ok: false, reason: "segment mapping failed" };
}
const argv = resolvePlannedSegmentArgv(seg);
if (!argv) {
return { ok: false, reason: "segment execution plan unavailable" };
}
return { ok: true, rendered: renderQuotedArgv(argv) };
},
});
if (!rebuilt.ok) {