File tree Expand file tree Collapse file tree 3 files changed +45
–2
lines changed
Expand file tree Collapse file tree 3 files changed +45
–2
lines changed Original file line number Diff line number Diff line change @@ -485,7 +485,9 @@ def set_headers(self, filelike):
485485 disposition = 'attachment' if self .as_attachment else 'inline'
486486 try :
487487 filename .encode ('ascii' )
488- file_expr = 'filename="{}"' .format (filename )
488+ file_expr = 'filename="{}"' .format (
489+ filename .replace ('\\ ' , '\\ \\ ' ).replace ('"' , r'\"' )
490+ )
489491 except UnicodeEncodeError :
490492 file_expr = "filename*=utf-8''{}" .format (quote (filename ))
491493 self .headers ['Content-Disposition' ] = '{}; {}' .format (disposition , file_expr )
Original file line number Diff line number Diff line change @@ -6,4 +6,10 @@ Django 3.2.15 release notes
66
77Django 3.2.15 fixes a security issue with severity "high" in 3.2.14.
88
9- ...
9+ CVE-2022-36359: Potential reflected file download vulnerability in ``FileResponse``
10+ ===================================================================================
11+
12+ An application may have been vulnerable to a reflected file download (RFD)
13+ attack that sets the Content-Disposition header of a
14+ :class:`~django.http.FileResponse` when the ``filename`` was derived from
15+ user-supplied input. The ``filename`` is now escaped to avoid this possibility.
Original file line number Diff line number Diff line change @@ -89,3 +89,38 @@ def test_unicode_attachment(self):
8989 response .headers ['Content-Disposition' ],
9090 "attachment; filename*=utf-8''%E7%A5%9D%E6%82%A8%E5%B9%B3%E5%AE%89.odt"
9191 )
92+
93+ def test_content_disposition_escaping (self ):
94+ # fmt: off
95+ tests = [
96+ (
97+ 'multi-part-one";\" dummy".txt' ,
98+ r"multi-part-one\";\" dummy\".txt"
99+ ),
100+ ]
101+ # fmt: on
102+ # Non-escape sequence backslashes are path segments on Windows, and are
103+ # eliminated by an os.path.basename() check in FileResponse.
104+ if sys .platform != "win32" :
105+ # fmt: off
106+ tests += [
107+ (
108+ 'multi-part-one\\ ";\" dummy".txt' ,
109+ r"multi-part-one\\\";\" dummy\".txt"
110+ ),
111+ (
112+ 'multi-part-one\\ ";\\ \" dummy".txt' ,
113+ r"multi-part-one\\\";\\\" dummy\".txt"
114+ )
115+ ]
116+ # fmt: on
117+ for filename , escaped in tests :
118+ with self .subTest (filename = filename , escaped = escaped ):
119+ response = FileResponse (
120+ io .BytesIO (b"binary content" ), filename = filename , as_attachment = True
121+ )
122+ response .close ()
123+ self .assertEqual (
124+ response .headers ["Content-Disposition" ],
125+ f'attachment; filename="{ escaped } "' ,
126+ )
You can’t perform that action at this time.
0 commit comments