fix(security): harden archive extraction (#16203)

* fix(browser): confine upload paths for file chooser

* fix(browser): sanitize suggested download filenames

* chore(lint): avoid control regex in download sanitizer

* test(browser): cover absolute escape paths

* docs(browser): update upload example path

* refactor(browser): centralize upload path confinement

* fix(infra): harden tmp dir selection

* fix(security): harden archive extraction

* fix(infra): harden tar extraction filter
This commit is contained in:
Peter Steinberger
2026-02-14 14:42:08 +01:00
committed by GitHub
parent 9a134c8a10
commit 3aa94afcfd
19 changed files with 1179 additions and 100 deletions

View File

@@ -4,6 +4,7 @@ import os from "node:os";
import path from "node:path";
import { fetch as realFetch } from "undici";
import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import { DEFAULT_UPLOAD_DIR } from "./paths.js";
let testPort = 0;
let cdpBaseUrl = "";
@@ -413,31 +414,31 @@ describe("browser control server", () => {
const base = await startServerAndBase();
const upload = await postJson(`${base}/hooks/file-chooser`, {
paths: ["/tmp/a.txt"],
paths: ["a.txt"],
timeoutMs: 1234,
});
expect(upload).toMatchObject({ ok: true });
expect(pwMocks.armFileUploadViaPlaywright).toHaveBeenCalledWith({
cdpUrl: cdpBaseUrl,
targetId: "abcd1234",
paths: ["/tmp/a.txt"],
paths: [path.join(DEFAULT_UPLOAD_DIR, "a.txt")],
timeoutMs: 1234,
});
const uploadWithRef = await postJson(`${base}/hooks/file-chooser`, {
paths: ["/tmp/b.txt"],
paths: ["b.txt"],
ref: "e12",
});
expect(uploadWithRef).toMatchObject({ ok: true });
const uploadWithInputRef = await postJson(`${base}/hooks/file-chooser`, {
paths: ["/tmp/c.txt"],
paths: ["c.txt"],
inputRef: "e99",
});
expect(uploadWithInputRef).toMatchObject({ ok: true });
const uploadWithElement = await postJson(`${base}/hooks/file-chooser`, {
paths: ["/tmp/d.txt"],
paths: ["d.txt"],
element: "input[type=file]",
});
expect(uploadWithElement).toMatchObject({ ok: true });