Skip to content

feat(media): allow text/html on the generic file-upload path - #4754

Open
TechPrieto wants to merge 2 commits into
block:mainfrom
TechPrieto:feat/relay-allow-html-uploads
Open

feat(media): allow text/html on the generic file-upload path#4754
TechPrieto wants to merge 2 commits into
block:mainfrom
TechPrieto:feat/relay-allow-html-uploads

Conversation

@TechPrieto

Copy link
Copy Markdown

Summary

Allow text/html through the generic file-upload path's deny-list (buzz-media/src/validation.rs::BLOCKED_FILE_MIME_TYPES). Depends on #4753 (mirrors the same removal in buzz-cli's client-side BLOCKED_MIMES).

Why: legitimate use case is sharing generated HTML reports/exports as chat attachments. The existing defence in depth already neutralizes the stored-XSS risk for any client that respects the response headers: generic (non-image/video) attachments are served with Content-Disposition: attachment, X-Content-Type-Options: nosniff, and Content-Security-Policy: default-src 'none' (buzz-relay/src/api/media.rs). This PR only removes the extra defence-in-depth layer for text/html specifically — application/xhtml+xml, JS, and SVG stay blocked, and executables stay blocked (zip them instead, already supported).

This is a deliberate, scoped risk trade-off made by a self-hosted instance owner for their own deployment — happy to discuss whether it belongs upstream as-is, behind a config flag, or not at all if the maintainers see a broader risk I'm not accounting for.

Test plan

  • cargo test -p buzz-media --lib — 108/108 passing, including new coverage: HTML is accepted and serve_inline still returns false for it (forced download), and a real XHTML-prologue document doesn't get misclassified as text/html
  • cargo test -p buzz-cli — 321/321 passing

🤖 Generated with Claude Code

@TechPrieto
TechPrieto requested a review from a team as a code owner August 4, 2026 17:27
buzz-cli's upload_file() rejected any MIME type outside a narrow
image/video allowlist before the file ever reached the relay. The
relay's /upload endpoint already routes non-image/video bytes through
buzz_media::process_file_upload — a generic-file path with its own
magic-byte sniffing, size cap, and deny-list for active-content/
executable types (buzz-media/src/validation.rs) — so the CLI's stricter
local check was purely redundant and blocked legitimate attachments
(docs, text, PDFs) that the server already supports.

Replace the local allowlist with a deny-list mirroring the relay's
BLOCKED_FILE_MIME_TYPES; anything else now uploads and lets the relay
be the authoritative validator, as designed.

Also fixes the markdown embed for non-image/video uploads: they were
rendered as broken `![image](url)` embeds. Desktop's resolveFileCard
renderer expects a markdown *link* (`[filename](url)`) plus the imeta
MIME to show a generic-file download card, so route those through a
`[filename](url)` link using the original filename (Blossom URLs are
content-hash-addressed, not human-readable).

Reported by Abraham in #buzz-ops 2026-08-04: Antigravity shared a
`file:///home/...` artifact link that only resolved on the VPS, not
from a remote Desktop client — this closes the underlying gap that
made pasting file:// paths the only option.
Owner decision (Abraham, #buzz-ops 2026-08-04): accept the residual
risk of hosting text/html attachments given the existing defence in
depth — generic files are already served with
`Content-Disposition: attachment`, `X-Content-Type-Options: nosniff`,
and `Content-Security-Policy: default-src 'none'`, which prevents an
accepted HTML upload from executing or rendering as active content in
any client that respects those headers. Use case: sharing generated
HTML reports/exports.

`application/xhtml+xml` stays blocked (not part of the request). JS
and SVG stay blocked (classic stored-XSS carriers, no legitimate need
raised). Executables stay blocked — the same conversation settled on
zipping installers/binaries instead, which was already supported.

Mirrors the same removal in buzz-cli's client-side BLOCKED_MIMES so
the CLI doesn't reject an upload the relay now accepts.
@TechPrieto
TechPrieto force-pushed the feat/relay-allow-html-uploads branch from 5f8ccbf to dae00ee Compare August 5, 2026 03:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant