6f4f7a1198
## Summary - File serving endpoints (`GET file/:fileFolder/:id` and `GET public-assets/...`) were piping S3/local file streams directly to the response without any HTTP headers, allowing a stored XSS attack via uploaded HTML files rendered inline on the CRM origin. - Adds `Content-Type`, `Content-Disposition`, and `X-Content-Type-Options: nosniff` headers to all file serving responses. Only known-safe MIME types (images, PDF, plain text, audio, video) are served inline; everything else (HTML, SVG, XML, etc.) forces `Content-Disposition: attachment` to trigger download instead of rendering. - New `setFileResponseHeaders` utility with an explicit allowlist of inline-safe MIME types. ## Test plan - [x] Unit tests pass (9 tests including 2 new ones: header assertions and attachment-disposition for HTML) - [x] Lint clean (`lint:diff-with-main`) - [x] Typecheck clean (`nx typecheck twenty-server`) - [ ] Manual: upload an HTML file via `uploadWorkflowFile`, access the returned URL — should download instead of rendering - [ ] Manual: upload a PNG image, access the URL — should render inline with correct `Content-Type: image/png` - [ ] Manual: verify `X-Content-Type-Options: nosniff` header is present on all file responses Made with [Cursor](https://cursor.com) --------- Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com> Co-authored-by: Etienne <etiennejouan@users.noreply.github.com> Co-authored-by: Etienne <45695613+etiennejouan@users.noreply.github.com>