mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-08 03:51:25 +00:00
Gateway: harden cron.runs jobId path handling (openclaw#24038) thanks @Takhoffman
Verified: - pnpm install --frozen-lockfile - pnpm build - pnpm check - pnpm test:macmini Co-authored-by: Takhoffman <781889+Takhoffman@users.noreply.github.com> Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
This commit is contained in:
@@ -25,6 +25,19 @@ describe("cron run log", () => {
|
||||
expect(p.endsWith(path.join(os.tmpdir(), "cron", "runs", "job-1.jsonl"))).toBe(true);
|
||||
});
|
||||
|
||||
it("rejects unsafe job ids when resolving run log path", () => {
|
||||
const storePath = path.join(os.tmpdir(), "cron", "jobs.json");
|
||||
expect(() => resolveCronRunLogPath({ storePath, jobId: "../job-1" })).toThrow(
|
||||
/invalid cron run log job id/i,
|
||||
);
|
||||
expect(() => resolveCronRunLogPath({ storePath, jobId: "nested/job-1" })).toThrow(
|
||||
/invalid cron run log job id/i,
|
||||
);
|
||||
expect(() => resolveCronRunLogPath({ storePath, jobId: "..\\job-1" })).toThrow(
|
||||
/invalid cron run log job id/i,
|
||||
);
|
||||
});
|
||||
|
||||
it("appends JSONL and prunes by line count", async () => {
|
||||
await withRunLogDir("openclaw-cron-log-", async (dir) => {
|
||||
const logPath = path.join(dir, "runs", "job-1.jsonl");
|
||||
|
||||
@@ -19,10 +19,27 @@ export type CronRunLogEntry = {
|
||||
nextRunAtMs?: number;
|
||||
} & CronRunTelemetry;
|
||||
|
||||
function assertSafeCronRunLogJobId(jobId: string): string {
|
||||
const trimmed = jobId.trim();
|
||||
if (!trimmed) {
|
||||
throw new Error("invalid cron run log job id");
|
||||
}
|
||||
if (trimmed.includes("/") || trimmed.includes("\\") || trimmed.includes("\0")) {
|
||||
throw new Error("invalid cron run log job id");
|
||||
}
|
||||
return trimmed;
|
||||
}
|
||||
|
||||
export function resolveCronRunLogPath(params: { storePath: string; jobId: string }) {
|
||||
const storePath = path.resolve(params.storePath);
|
||||
const dir = path.dirname(storePath);
|
||||
return path.join(dir, "runs", `${params.jobId}.jsonl`);
|
||||
const runsDir = path.resolve(dir, "runs");
|
||||
const safeJobId = assertSafeCronRunLogJobId(params.jobId);
|
||||
const resolvedPath = path.resolve(runsDir, `${safeJobId}.jsonl`);
|
||||
if (!resolvedPath.startsWith(`${runsDir}${path.sep}`)) {
|
||||
throw new Error("invalid cron run log job id");
|
||||
}
|
||||
return resolvedPath;
|
||||
}
|
||||
|
||||
const writesByPath = new Map<string, Promise<void>>();
|
||||
|
||||
Reference in New Issue
Block a user