From be08e6c8a8a45262d050050ab160ca4e6b709b20 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Sat, 30 May 2026 23:40:24 +0100 Subject: [PATCH] fix(browser): reject normalized media traversal --- extensions/browser/src/browser/paths.test.ts | 18 ++++++++++++++++++ extensions/browser/src/browser/paths.ts | 7 ++++++- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/extensions/browser/src/browser/paths.test.ts b/extensions/browser/src/browser/paths.test.ts index bbf651e657f..9489d681c85 100644 --- a/extensions/browser/src/browser/paths.test.ts +++ b/extensions/browser/src/browser/paths.test.ts @@ -345,6 +345,24 @@ describe("resolveExistingUploadPaths", () => { }); }); + it("rejects traversal-shaped inbound media URI references before URL normalization", async () => { + await withFixtureRoot(async ({ inboundMediaDir, uploadsDir }) => { + const inboundFile = path.join(inboundMediaDir, "report.pdf"); + await fs.writeFile(inboundFile, "pdf", "utf8"); + + const result = await resolveExistingUploadPaths({ + uploadDir: uploadsDir, + inboundMediaDir, + requestedPaths: ["media://inbound/nested/../report.pdf"], + }); + + expect(result.ok).toBe(false); + if (!result.ok) { + expect(result.error).toContain("Invalid media reference"); + } + }); + }); + it("rejects nested absolute inbound media paths", async () => { await withFixtureRoot(async ({ inboundMediaDir, uploadsDir }) => { const nestedDir = path.join(inboundMediaDir, "nested"); diff --git a/extensions/browser/src/browser/paths.ts b/extensions/browser/src/browser/paths.ts index 3d301fc4ded..994e99cc84a 100644 --- a/extensions/browser/src/browser/paths.ts +++ b/extensions/browser/src/browser/paths.ts @@ -94,6 +94,8 @@ function resolveManagedInboundMediaRef( } if (/^media:\/\//i.test(normalizedSource)) { + const rawUriMatch = /^media:\/\/[^/?#]*([^?#]*)/iu.exec(normalizedSource); + const rawPath = rawUriMatch?.[1] ?? ""; let parsed: URL; try { parsed = new URL(normalizedSource); @@ -106,7 +108,10 @@ function resolveManagedInboundMediaRef( error: `Unsupported media reference location: ${parsed.hostname || "(missing)"}`, }; } - const decoded = decodeInboundMediaId(parsed.pathname.replace(/^\/+/, ""), normalizedSource); + if (!rawPath.startsWith("/") || rawPath.slice(1).includes("/") || rawPath.includes("\\")) { + return { ok: false, error: `Invalid media reference: ${normalizedSource}` }; + } + const decoded = decodeInboundMediaId(rawPath.slice(1), normalizedSource); return decoded?.ok ? { ok: true,