feat(media): allow text/html on the generic file-upload path - #4754
Open
TechPrieto wants to merge 2 commits into
Open
feat(media): allow text/html on the generic file-upload path#4754TechPrieto wants to merge 2 commits into
TechPrieto wants to merge 2 commits into
Conversation
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 `` 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
force-pushed
the
feat/relay-allow-html-uploads
branch
from
August 5, 2026 03:40
5f8ccbf to
dae00ee
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Allow
text/htmlthrough the generic file-upload path's deny-list (buzz-media/src/validation.rs::BLOCKED_FILE_MIME_TYPES). Depends on #4753 (mirrors the same removal inbuzz-cli's client-sideBLOCKED_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, andContent-Security-Policy: default-src 'none'(buzz-relay/src/api/media.rs). This PR only removes the extra defence-in-depth layer fortext/htmlspecifically —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 andserve_inlinestill returns false for it (forced download), and a real XHTML-prologue document doesn't get misclassified astext/htmlcargo test -p buzz-cli— 321/321 passing🤖 Generated with Claude Code