mirror of https://github.com/openclaw/openclaw.git
Exec approvals: reject shell init-file script matches (#58369)
This commit is contained in:
parent
0ed4f8a72b
commit
0c83754246
|
|
@ -120,6 +120,30 @@ describe("resolveAllowAlwaysPatterns", () => {
|
|||
expect(second.allowlistSatisfied).toBe(true);
|
||||
}
|
||||
|
||||
function expectShellScriptFallbackRejected(command: string) {
|
||||
const { dir, scriptsDir, script, env, safeBins } = createShellScriptFixture();
|
||||
const rcFile = path.join(scriptsDir, "evilrc");
|
||||
fs.writeFileSync(rcFile, "echo blocked\n");
|
||||
|
||||
const { persisted } = resolvePersistedPatterns({
|
||||
command,
|
||||
dir,
|
||||
env,
|
||||
safeBins,
|
||||
});
|
||||
expect(persisted).toEqual([]);
|
||||
|
||||
const second = evaluateShellAllowlist({
|
||||
command,
|
||||
allowlist: [{ pattern: script }],
|
||||
safeBins,
|
||||
cwd: dir,
|
||||
env,
|
||||
platform: process.platform,
|
||||
});
|
||||
expect(second.allowlistSatisfied).toBe(false);
|
||||
}
|
||||
|
||||
function expectPositionalArgvCarrierRejected(command: string) {
|
||||
const dir = makeTempDir();
|
||||
const touch = makeExecutable(dir, "touch");
|
||||
|
|
@ -283,6 +307,32 @@ describe("resolveAllowAlwaysPatterns", () => {
|
|||
});
|
||||
});
|
||||
|
||||
it("rejects shell rc and init-file options as persisted or allowlisted script paths", () => {
|
||||
if (process.platform === "win32") {
|
||||
return;
|
||||
}
|
||||
for (const command of [
|
||||
"bash --rcfile scripts/evilrc scripts/save_crystal.sh",
|
||||
"bash --init-file scripts/evilrc scripts/save_crystal.sh",
|
||||
"bash --startup-file scripts/evilrc scripts/save_crystal.sh",
|
||||
]) {
|
||||
expectShellScriptFallbackRejected(command);
|
||||
}
|
||||
});
|
||||
|
||||
it("rejects shell rc and init-file equals options as persisted or allowlisted script paths", () => {
|
||||
if (process.platform === "win32") {
|
||||
return;
|
||||
}
|
||||
for (const command of [
|
||||
"bash --rcfile=scripts/evilrc scripts/save_crystal.sh",
|
||||
"bash --init-file=scripts/evilrc scripts/save_crystal.sh",
|
||||
"bash --startup-file=scripts/evilrc scripts/save_crystal.sh",
|
||||
]) {
|
||||
expectShellScriptFallbackRejected(command);
|
||||
}
|
||||
});
|
||||
|
||||
it("rejects shell-wrapper positional argv carriers", () => {
|
||||
if (process.platform === "win32") {
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -504,16 +504,19 @@ function isShellWrapperSegment(segment: ExecCommandSegment): boolean {
|
|||
return hasSegmentExecutableMatch(segment, isShellWrapperExecutable);
|
||||
}
|
||||
|
||||
const SHELL_WRAPPER_OPTIONS_WITH_VALUE = new Set([
|
||||
"-c",
|
||||
"--command",
|
||||
"-o",
|
||||
"-O",
|
||||
"+O",
|
||||
const SHELL_WRAPPER_OPTIONS_WITH_VALUE = new Set(["-c", "--command", "-o", "-O", "+O"]);
|
||||
|
||||
const SHELL_WRAPPER_DISQUALIFYING_SCRIPT_OPTIONS = [
|
||||
"--rcfile",
|
||||
"--init-file",
|
||||
"--startup-file",
|
||||
]);
|
||||
] as const;
|
||||
|
||||
function hasDisqualifyingShellWrapperScriptOption(token: string): boolean {
|
||||
return SHELL_WRAPPER_DISQUALIFYING_SCRIPT_OPTIONS.some(
|
||||
(option) => token === option || token.startsWith(`${option}=`),
|
||||
);
|
||||
}
|
||||
|
||||
function resolveShellWrapperScriptCandidatePath(params: {
|
||||
segment: ExecCommandSegment;
|
||||
|
|
@ -548,6 +551,9 @@ function resolveShellWrapperScriptCandidatePath(params: {
|
|||
if (token === "-s" || /^-[^-]*s[^-]*$/i.test(token)) {
|
||||
return undefined;
|
||||
}
|
||||
if (hasDisqualifyingShellWrapperScriptOption(token)) {
|
||||
return undefined;
|
||||
}
|
||||
if (SHELL_WRAPPER_OPTIONS_WITH_VALUE.has(token)) {
|
||||
idx += 2;
|
||||
continue;
|
||||
|
|
|
|||
Loading…
Reference in New Issue