CVE-2023-28837 (Python, published 2023-04-03T17:15Z)
Description: value: Wagtail is an open source content management system built on Django. Prior to versions 4.1.4 and 4.2.2, a memory exhaustion bug exists in Wagtail's handling of uploaded images and documents. For both images and documents, files are loaded into memory during upload for additional processing. A user with access to upload images or documents through the Wagtail admin interface could upload a file so large that it results in a crash of denial of service.

The vulnerability is not exploitable by an ordinary site visitor without access to the Wagtail admin. It can only be exploited by admin users with permission to upload images or documents.

Image uploads are restricted to 10MB by default, however this validation only happens on the frontend and on the backend after the vulnerable code. 

Patched versions have been released as Wagtail 4.1.4 and Wagtail 4.2.2). Site owners who are unable to upgrade to the new versions are encouraged to add extra protections outside of Wagtail to limit the size of uploaded files.
Severity: nan (CVSS v3 base score: 4.9)
Weakness: CWE-770 \u2014 Allocation of Resources Without Limits or Throttling
The product allocates a reusable resource or group of resources on behalf of an actor without imposing any restrictions on the size or number of resources that can be allocated, in violation of the intended security policy for that actor.
Repository: https://github.com/wagtail/wagtail
Files changed:
wagtail/images/fields.py
wagtail/images/tests/test_admin_views.py
Commit message: Don't load temporary uploaded files into memory

These can be quite large. Instead pass them straight to Willow to have it read just as much as it needs to


Vulnerable code:
        # We need to get a file object for Pillow. When we get a path, we need to open
        # the file first. And we have to read the data into memory to pass to Willow.
            with open(data.temporary_file_path(), "rb") as fh:
                file = BytesIO(fh.read())
from django.core.files.uploadedfile import SimpleUploadedFile

Fixed code:
        # Get the file content ready for Willow
            # Django's `TemporaryUploadedFile` is enough of a file to satisfy Willow
            # Willow doesn't support opening images by path https://github.com/wagtail/Willow/issues/108
            file = data
from django.core.files.uploadedfile import SimpleUploadedFile, TemporaryUploadedFile
    def test_add_temporary_uploaded_file(self):
        """
        Test that uploading large files (spooled to the filesystem) work as expected
        """
        test_image_file = get_test_image_file()
        uploaded_file = TemporaryUploadedFile(
            "test.png", "image/png", test_image_file.size, "utf-8"
        )
        uploaded_file.write(test_image_file.file.getvalue())
        uploaded_file.seek(0)

        response = self.post(
            {
                "title": "Test image",
                "file": uploaded_file,
            }
        )

        # Should redirect back to index
        self.assertRedirects(response, reverse("wagtailimages:index"))

        # Check that the image was created
        images = Image.objects.filter(title="Test image")
        self.assertEqual(images.count(), 1)

        # Test that size was populated correctly
        image = images.first()
        self.assertEqual(image.width, 640)
        self.assertEqual(image.height, 480)

        # Test that the file_size/hash fields were set
        self.assertTrue(image.file_size)
        self.assertTrue(image.file_hash)

        # Test that it was placed in the root collection
        root_collection = Collection.get_first_root_node()
        self.assertEqual(image.collection, root_collection)