From abb249e5df4660fde52350b4abb39b2c744c77e8 Mon Sep 17 00:00:00 2001 From: Linus Rath <139418639+rathlinus@users.noreply.github.com> Date: Sun, 31 May 2026 15:25:08 +0200 Subject: [PATCH] Fix: gate preview "open in new tab" on inline-safe MIME types The header open-in-new-tab button opened the blob: URL as a top-level navigation for any preview that produced an objectUrl, including HTML and SVG attachments. Blob URLs inherit our origin, so a script-bearing attachment (text/html, image/svg+xml, ...) would execute in-origin when opened that way - the exact case isMimeTypeSafeForInlinePreview() already guards. Gate the button on that helper so it only appears for inert types (images except SVG, audio, video, PDF, text/plain). --- components/files/file-preview-modal.tsx | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/components/files/file-preview-modal.tsx b/components/files/file-preview-modal.tsx index e1beedcd..ec9fd515 100644 --- a/components/files/file-preview-modal.tsx +++ b/components/files/file-preview-modal.tsx @@ -4,7 +4,7 @@ import { useState, useEffect, useRef } from "react"; import { useTranslations } from "next-intl"; import { X, Download, Loader2, ExternalLink } from "lucide-react"; import { Button } from "@/components/ui/button"; -import { getFilePreviewKind } from "@/lib/file-preview"; +import { getFilePreviewKind, isMimeTypeSafeForInlinePreview } from "@/lib/file-preview"; import dynamic from "next/dynamic"; // pdf.js-based inline viewer for mobile (no native inline PDF viewer). Loaded @@ -149,6 +149,10 @@ export function FilePreviewModal({ name, onClose, onDownload, getFileContent }: const [error, setError] = useState(false); const [resolvedFileType, setResolvedFileType] = useState(() => getFilePreviewKind(name)); const [pdfInlineSupported, setPdfInlineSupported] = useState(true); + // Whether the resolved blob MIME is inert enough to open as a top-level + // navigation. Blob URLs inherit our origin, so opening a script-bearing type + // (text/html, image/svg+xml, ...) in a new tab would execute it in-origin. + const [canOpenInNewTab, setCanOpenInNewTab] = useState(false); // Decide whether to render the PDF in a plain