- Shipped
- September 23, 2026 at 10:10 AM UTC
- Author
- Kamo
- Commit
- d8971bc
GET/HEAD **************** always answered with the client-declared Content-Type from upload, no Content-Disposition, no X-Content-Type-Options and no CSP. ChatAttachmentService's upload allow-list admits image/* including image/svg+xml, and an SVG document can carry a <script> - so an attachment stored as image/svg+xml and opened by URL ran as the response's own document, on kamo-internal's host where the *** cookie is httpOnly:false (prod already held three SVG chat attachments). The chat bubble's own <img> already refuses to inline SVG **************** so this was only reachable by opening the attachment's URL directly, not through the normal chat view - but the URL is exactly what a "download"/"open" affordance on a non-image attachment chip has to link to. The endpoint now always sends X-Content-Type-Options: nosniff and a restrictive Content-Security-Policy (default-src 'none'; sandbox; ...), and adds Content-Disposition: attachment for anything outside a small allow-list of raster image types plus audio/* and video/* (which Range-stream through this same endpoint and must stay inline to keep playing). Nothing in the allow-list changed - SVG, PDF and any other document-shaped upload still succeed, they just can no longer render as a page when someone opens the attachment's URL. kamo-internal's own relay of this route **************** only forwards **************** so it currently strips these new headers back out before they reach a browser - flagged for the coordinator to fix on that side; this commit is the mediaservice half. Covered by ImagingProxyContentSecurityTest (mutation-checked: reverting the new header block turns all four assertions red).
