mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-09 00:28:26 +00:00
Security/Browser: constrain trace and download output paths to OpenClaw temp roots (#15652)
* Browser/Security: constrain trace and download output paths to temp roots * Changelog: remove advisory ID from pre-public security note * Browser/Security: constrain trace and download output paths to temp roots * Changelog: remove advisory ID from pre-public security note * test(bluebubbles): align timeout status expectation to 408 * test(discord): remove unused race-condition counter in threading test * test(bluebubbles): align timeout status expectation to 408
This commit is contained in:
@@ -49,6 +49,7 @@ const pwMocks = vi.hoisted(() => ({
|
||||
selectOptionViaPlaywright: vi.fn(async () => {}),
|
||||
setInputFilesViaPlaywright: vi.fn(async () => {}),
|
||||
snapshotAiViaPlaywright: vi.fn(async () => ({ snapshot: "ok" })),
|
||||
traceStopViaPlaywright: vi.fn(async () => {}),
|
||||
takeScreenshotViaPlaywright: vi.fn(async () => ({
|
||||
buffer: Buffer.from("png"),
|
||||
})),
|
||||
@@ -434,14 +435,14 @@ describe("browser control server", () => {
|
||||
expect(dialog).toMatchObject({ ok: true });
|
||||
|
||||
const waitDownload = await postJson(`${base}/wait/download`, {
|
||||
path: "/tmp/report.pdf",
|
||||
path: "report.pdf",
|
||||
timeoutMs: 1111,
|
||||
});
|
||||
expect(waitDownload).toMatchObject({ ok: true });
|
||||
|
||||
const download = await postJson(`${base}/download`, {
|
||||
ref: "e12",
|
||||
path: "/tmp/report.pdf",
|
||||
path: "report.pdf",
|
||||
});
|
||||
expect(download).toMatchObject({ ok: true });
|
||||
|
||||
@@ -480,4 +481,83 @@ describe("browser control server", () => {
|
||||
expect(stopped.ok).toBe(true);
|
||||
expect(stopped.stopped).toBe(true);
|
||||
});
|
||||
|
||||
it("trace stop rejects traversal path outside trace dir", async () => {
|
||||
const base = await startServerAndBase();
|
||||
const res = await postJson<{ error?: string }>(`${base}/trace/stop`, {
|
||||
path: "../../pwned.zip",
|
||||
});
|
||||
expect(res.error).toContain("Invalid path");
|
||||
expect(pwMocks.traceStopViaPlaywright).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("trace stop accepts in-root relative output path", async () => {
|
||||
const base = await startServerAndBase();
|
||||
const res = await postJson<{ ok?: boolean; path?: string }>(`${base}/trace/stop`, {
|
||||
path: "safe-trace.zip",
|
||||
});
|
||||
expect(res.ok).toBe(true);
|
||||
expect(res.path).toContain("safe-trace.zip");
|
||||
expect(pwMocks.traceStopViaPlaywright).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
cdpUrl: cdpBaseUrl,
|
||||
targetId: "abcd1234",
|
||||
path: expect.stringContaining("safe-trace.zip"),
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it("wait/download rejects traversal path outside downloads dir", async () => {
|
||||
const base = await startServerAndBase();
|
||||
const waitRes = await postJson<{ error?: string }>(`${base}/wait/download`, {
|
||||
path: "../../pwned.pdf",
|
||||
});
|
||||
expect(waitRes.error).toContain("Invalid path");
|
||||
expect(pwMocks.waitForDownloadViaPlaywright).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("download rejects traversal path outside downloads dir", async () => {
|
||||
const base = await startServerAndBase();
|
||||
const downloadRes = await postJson<{ error?: string }>(`${base}/download`, {
|
||||
ref: "e12",
|
||||
path: "../../pwned.pdf",
|
||||
});
|
||||
expect(downloadRes.error).toContain("Invalid path");
|
||||
expect(pwMocks.downloadViaPlaywright).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("wait/download accepts in-root relative output path", async () => {
|
||||
const base = await startServerAndBase();
|
||||
const res = await postJson<{ ok?: boolean; download?: { path?: string } }>(
|
||||
`${base}/wait/download`,
|
||||
{
|
||||
path: "safe-wait.pdf",
|
||||
},
|
||||
);
|
||||
expect(res.ok).toBe(true);
|
||||
expect(pwMocks.waitForDownloadViaPlaywright).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
cdpUrl: cdpBaseUrl,
|
||||
targetId: "abcd1234",
|
||||
path: expect.stringContaining("safe-wait.pdf"),
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it("download accepts in-root relative output path", async () => {
|
||||
const base = await startServerAndBase();
|
||||
const res = await postJson<{ ok?: boolean; download?: { path?: string } }>(`${base}/download`, {
|
||||
ref: "e12",
|
||||
path: "safe-download.pdf",
|
||||
});
|
||||
expect(res.ok).toBe(true);
|
||||
expect(pwMocks.downloadViaPlaywright).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
cdpUrl: cdpBaseUrl,
|
||||
targetId: "abcd1234",
|
||||
ref: "e12",
|
||||
path: expect.stringContaining("safe-download.pdf"),
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user