diff --git a/django/core/files/storage.py b/django/core/files/storage.py index d8423f0600..cc91f67b07 100644 --- a/django/core/files/storage.py +++ b/django/core/files/storage.py @@ -405,7 +405,10 @@ class FileSystemStorage(Storage): def url(self, name): if self.base_url is None: raise ValueError("This file is not accessible via a URL.") - return urljoin(self.base_url, filepath_to_uri(name)) + url = filepath_to_uri(name) + if url is not None: + url = url.lstrip('/') + return urljoin(self.base_url, url) def accessed_time(self, name): warnings.warn( diff --git a/tests/file_storage/tests.py b/tests/file_storage/tests.py index 7257f29b29..e027d51249 100644 --- a/tests/file_storage/tests.py +++ b/tests/file_storage/tests.py @@ -399,11 +399,24 @@ class FileStorageTests(TestCase): # like encodeURIComponent() JavaScript function do self.assertEqual(self.storage.url(r"""~!*()'@#$%^&*abc`+ =.file"""), """/test_media_url/~!*()'%40%23%24%25%5E%26*abc%60%2B%20%3D.file""") + self.assertEqual(self.storage.url("""ab\0c"""), """/test_media_url/ab%00c""") # should translate os path separator(s) to the url path separator self.assertEqual(self.storage.url("""a/b\\c.file"""), """/test_media_url/a/b/c.file""") + # #25905: remove leading slashes from file names to prevent unsafe url output + self.assertEqual(self.storage.url("/evil.com"), "/test_media_url/evil.com") + self.assertEqual(self.storage.url(r"\evil.com"), "/test_media_url/evil.com") + self.assertEqual(self.storage.url("///evil.com"), "/test_media_url/evil.com") + self.assertEqual(self.storage.url(r"\\\evil.com"), "/test_media_url/evil.com") + + self.assertEqual(self.storage.url(None), "/test_media_url/") + + def test_base_url(self): + """ + File storage returns a url even when its base_url is unset or modified. + """ self.storage.base_url = None with self.assertRaises(ValueError): self.storage.url('test.file')