fix(proxy): allow same-origin framing of the document serve route

The blanket X-Frame-Options: DENY + frame-ancestors 'none' refused the
detail preview's same-origin <iframe>, and the middleware page CSP
clobbered whatever the serve route set — the inline PDF preview rendered
as a permanent skeleton. Carve out exactly the /original path:
SAMEORIGIN framing, frame-ancestors 'self', and a document CSP of
default-src 'none'. Deliberately NO sandbox directive and no sandbox
attribute on the preview iframe — Chromium force-downloads PDFs in
sandboxed documents instead of rendering them (verified against a real
Chromium channel; headless test builds ship no PDF viewer at all). The
load-bearing boundaries for user-uploaded bytes are unchanged:
magic-byte classification at upload, true Content-Type + nosniff at
serve, HTML/SVG denied entirely, attachment-only posture for every
non-passive format. Tests pin the carve-out and that every neighbouring
path keeps the DENY posture.

Plan-Task: W2-T3 (preview integration)
This commit is contained in:
Marc-André Bombeck committed 2026-07-07 12:57:12 +02:00
1 parent 2b7a6544d6
commit f9ca7fef79
3 files changed
+127 -5

No files matched your search

@@ -87,10 +87,15 @@ function InlinePreview({
/>
) : null}
{isPdf ? (
// No `sandbox` attribute by design: Chromium force-downloads PDFs
// in sandboxed frames instead of rendering them. The serve
// response itself carries `default-src 'none'` +
// `frame-ancestors 'self'` + true Content-Type + nosniff, and the
// upload policy denies every format whose inline render could
// execute script.
<iframe
src={src}
title={title}
sandbox=""
onLoad={() => setLoaded(true)}
className={cn(
"border-border h-[55vh] w-full rounded-lg border",