ποΈ(backend) force SVG attachments to download to prevent stored XSS - #2582
ποΈ(backend) force SVG attachments to download to prevent stored XSS#2582bunlongheng wants to merge 1 commit into
Conversation
|
No actionable comments were generated in the recent review. π βΉοΈ Recent review infoβοΈ Run configurationConfiguration used: Repository UI Review profile: ASSERTIVE Plan: Pro Plus Run ID: π Files selected for processing (1)
WalkthroughThe unsafe document MIME-type configuration now includes Estimated code review effort: 1 (Trivial) | ~2 minutes Mergeability Score: βͺ Minimal Β· up to SVG attachments will be forced to download instead of rendering inline; no actionable merge-blocking risk remains at the current head after normal checks and review. Suggested reviewers: π₯ Pre-merge checks | β 5β Passed checks (5 passed)
β¨ Finishing Touchesπ§ͺ Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
I've already come across this, but i think this claim is wrong:
You can check the nginx config here: https://github.com/suitenumerique/docs/blob/main/docker/files/etc/nginx/conf.d/default.conf So all scripting falls back to 'none'. The XSS can't be triggered, and your POC isn't reproducible. |
Summary
Uploaded SVG attachments are served inline with
Content-Type: image/svg+xml, allowing stored XSS in the application origin.image/svg+xmlis missing fromDOCUMENT_UNSAFE_MIME_TYPES, so an SVG passes theis_unsafecheck andattachment_uploadsetsContent-Disposition: inline(thecontent_type.startswith("image/")branch). SVG documents can carry<script>and event handlers that execute when the file is opened directly.Impact
/media/(defaultMEDIA_URL = "/media/",MEDIA_BASE_URL = None).CONTENT_SECURITY_POLICYonly applies to Django responses; attachment files are served by the object storage backend via the nginxmedia-authsubrequest, so theContent-Type/Content-Dispositioncome from S3 object metadata and no CSP ornosniffheader is applied to them..svg(libmagic reportsimage/svg+xml, which matches the filename extension, so the existing extension-mismatch guard does not flag it). Any user who opens that attachment URL executes attacker-controlled JavaScript in the app origin, enabling session/cookie theft (CORS_ALLOW_CREDENTIALS = True). Documents with a public link reach make this reachable by any visitor.Reproduction
<script>alert(document.domain)</script>, namedpoc.svg.is_unsafe=false,Content-Type: image/svg+xml,Content-Disposition: inline.Fix
Add
image/svg+xmltoDOCUMENT_UNSAFE_MIME_TYPES. Detected SVGs are then flaggedis_unsafe=true, which makesattachment_uploadsetContent-Disposition: attachment(forced download) and append the-unsafesuffix, matching the existing handling for other active-content types. Raster image uploads (png, jpeg, ...) are unaffected and still served inline.This mirrors the existing treatment of
application/xhtml+xml,text/html, and script MIME types already in the list.