A RetroSearch Logo

Home - News ( United States | United Kingdom | Italy | Germany ) - Football scores

Search Query:

Showing content from https://github.com/django/django/commit/4cb35b384ceef52123fc66411a73c36a706825e1 below:

[2.2.x] Fixed CVE-2021-45452 -- Fixed potential path traversal in sto… · django/django@4cb35b3 · GitHub

File tree Expand file treeCollapse file tree 4 files changed

+36

-7

lines changed

Filter options

Expand file treeCollapse file tree 4 files changed

+36

-7

lines changed Original file line number Diff line number Diff line change

@@ -51,7 +51,10 @@ def save(self, name, content, max_length=None):

51 51

content = File(content, name)

52 52 53 53

name = self.get_available_name(name, max_length=max_length)

54 -

return self._save(name, content)

54 +

name = self._save(name, content)

55 +

# Ensure that the name returned from the storage system is still valid.

56 +

validate_file_name(name, allow_relative_path=True)

57 +

return name

55 58 56 59

# These methods are part of the public API, with default implementations.

57 60

@@ -67,6 +70,7 @@ def get_available_name(self, name, max_length=None):

67 70

Return a filename that's free on the target storage system and

68 71

available for new content to be written to.

69 72

"""

73 +

name = str(name).replace('\\', '/')

70 74

dir_name, file_name = os.path.split(name)

71 75

if '..' in pathlib.PurePath(dir_name).parts:

72 76

raise SuspiciousFileOperation("Detected path traversal attempt in '%s'" % dir_name)

@@ -101,6 +105,7 @@ def generate_filename(self, filename):

101 105

Validate the filename by calling get_valid_name() and return a filename

102 106

to be passed to the save() method.

103 107

"""

108 +

filename = str(filename).replace('\\', '/')

104 109

# `filename` may include a path as returned by FileField.upload_to.

105 110

dirname, filename = os.path.split(filename)

106 111

if '..' in pathlib.PurePath(dirname).parts:

@@ -296,6 +301,8 @@ def _save(self, name, content):

296 301

if self.file_permissions_mode is not None:

297 302

os.chmod(full_path, self.file_permissions_mode)

298 303 304 +

# Ensure the saved path is always relative to the storage root.

305 +

name = os.path.relpath(full_path, self.location)

299 306

# Store filenames with forward slashes, even on Windows.

300 307

return name.replace('\\', '/')

301 308 Original file line number Diff line number Diff line change

@@ -36,3 +36,12 @@ As a reminder, all untrusted user input should be validated before use.

36 36 37 37

This issue has severity "low" according to the :ref:`Django security policy

38 38

<security-disclosure>`.

39 + 40 +

CVE-2021-45452: Potential directory-traversal via ``Storage.save()``

41 +

====================================================================

42 + 43 +

``Storage.save()`` allowed directory-traversal if directly passed suitably

44 +

crafted file names.

45 + 46 +

This issue has severity "low" according to the :ref:`Django security policy

47 +

<security-disclosure>`.

Original file line number Diff line number Diff line change

@@ -53,13 +53,20 @@ def test_storage_dangerous_paths(self):

53 53

s.generate_filename(file_name)

54 54 55 55

def test_storage_dangerous_paths_dir_name(self):

56 -

file_name = '/tmp/../path'

56 +

candidates = [

57 +

('tmp/../path', 'tmp/..'),

58 +

('tmp\\..\\path', 'tmp/..'),

59 +

('/tmp/../path', '/tmp/..'),

60 +

('\\tmp\\..\\path', '/tmp/..'),

61 +

]

57 62

s = FileSystemStorage()

58 -

msg = "Detected path traversal attempt in '/tmp/..'"

59 -

with self.assertRaisesMessage(SuspiciousFileOperation, msg):

60 -

s.get_available_name(file_name)

61 -

with self.assertRaisesMessage(SuspiciousFileOperation, msg):

62 -

s.generate_filename(file_name)

63 +

for file_name, path in candidates:

64 +

msg = "Detected path traversal attempt in '%s'" % path

65 +

with self.subTest(file_name=file_name):

66 +

with self.assertRaisesMessage(SuspiciousFileOperation, msg):

67 +

s.get_available_name(file_name)

68 +

with self.assertRaisesMessage(SuspiciousFileOperation, msg):

69 +

s.generate_filename(file_name)

63 70 64 71

def test_filefield_dangerous_filename(self):

65 72

candidates = [

Original file line number Diff line number Diff line change

@@ -291,6 +291,12 @@ def test_file_save_with_path(self):

291 291 292 292

self.storage.delete('path/to/test.file')

293 293 294 +

def test_file_save_abs_path(self):

295 +

test_name = 'path/to/test.file'

296 +

f = ContentFile('file saved with path')

297 +

f_name = self.storage.save(os.path.join(self.temp_dir, test_name), f)

298 +

self.assertEqual(f_name, test_name)

299 + 294 300

def test_save_doesnt_close(self):

295 301

with TemporaryUploadedFile('test', 'text/plain', 1, 'utf8') as file:

296 302

file.write(b'1')

You can’t perform that action at this time.


RetroSearch is an open source project built by @garambo | Open a GitHub Issue

Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo

HTML: 3.2 | Encoding: UTF-8 | Version: 0.7.4