Skip to content

[Bug]: PDF preview broken - sandbox="allow-scripts" on blob iframe blocks rendering #253

@tstreule

Description

@tstreule

Description

PDF previews fail to render in Chrome, Safari, and Chromium derivatives. In components/files/file-preview-modal.tsx:

<iframe src={objectUrl} sandbox="allow-scripts" ... />

sandbox="allow-scripts" without allow-same-origin puts the iframe in a unique opaque origin, so loading the parent-minted blob URL is treated as a cross-origin navigation and blocked by Chromium. Safari additionally never renders PDFs inside <iframe> — it requires <object> / <embed>.

Steps to Reproduce

  1. Open an email with a PDF attachment.
  2. Click the PDF to preview.
docker-compose.yml
services:
  webmail:
    image: ghcr.io/bulwarkmail/webmail:latest
    container_name: webmail
    restart: unless-stopped
    expose:
      - "3000"
    env_file: .env
    environment:
      HOSTNAME: 0.0.0.0
      PORT: "3000"
      ALLOWED_FRAME_ANCESTORS: "'self'"
    volumes:
      - bulwark-settings:/app/data/settings
      - bulwark-admin:/app/data/admin
      - bulwark-telemetry:/app/data/telemetry
    healthcheck:
      test:
        [
          "CMD",
          "wget",
          "--no-verbose",
          "--tries=1",
          "--spider",
          "http://127.0.0.1:3000/api/health",
        ]
      interval: 30s
      timeout: 5s
      retries: 3
      start_period: 10s

volumes:
  bulwark-settings:
  bulwark-admin:
  bulwark-telemetry:

Expected Behavior

PDF renders inline using the browser's built-in viewer.

Actual Behavior

  • Chrome / Dia: iframe shows "This page has been blocked by Chrome/Dia". DevTools logs the blob document as (blocked:other).
  • Safari: blank iframe, no console output.

JMAP fetch of the blob succeeds in all cases; the failure is in rendering.

Bulwark Version

latest (verified against commit b5e0189)

Stalwart Mail Server Version

0.16.3

Browser

Chrome / Chromium, Safari

Operating System

macOS

Screenshots / Screen Recording

Dia (Chromium based) Safari
Image Image

Relevant Logs or Error Output

blob:https://webmail.example/<uuid>    (blocked:other)    document    184 kB

Additional Context

Suggested fix — replace the iframe with <object> and drop the sandbox (the browser's PDF viewer is already isolated):

<object
  data={objectUrl}
  type="application/pdf"
  className="w-full max-w-5xl h-full rounded-lg bg-white"
  aria-label={name}
>
  <Button onClick={() => void onDownload()}>
    <Download className="w-4 h-4 mr-2" />
    {t("download")}
  </Button>
</object>

This should work in Safari (which renders PDFs via <object>) and avoid the sandbox/blob-origin mismatch in Chromium.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions