thumbnail: Lock down which formats we parse.

This commit is contained in:
Alex Vandiver 2024-07-11 02:50:44 +00:00 committed by Tim Abbott
parent 4bc563128e
commit 382cb5bb13
3 changed files with 26 additions and 1 deletions

View File

@ -29,7 +29,8 @@ MAX_EMOJI_GIF_FILE_SIZE_BYTES = 128 * 1024 # 128 kb
# provided by the browser, and may not match the bytes they uploaded.
#
# This should be kept synced with the client-side image-picker in
# web/upload_widget.ts.
# web/upload_widget.ts. Any additions below must be accompanied by
# changes to the pyvips block below as well.
THUMBNAIL_ACCEPT_IMAGE_TYPES = frozenset(
[
"image/avif",
@ -42,6 +43,23 @@ THUMBNAIL_ACCEPT_IMAGE_TYPES = frozenset(
]
)
# This is what enforces security limitations on which formats are
# parsed; we disable all loaders, then re-enable the ones we support
# -- then explicitly disable any "untrusted" ones, in case libvips for
# some reason marks one of the above formats as such (because they are
# no longer fuzzed, for instance).
#
# Note that only libvips >= 8.13 (Uubntu 24.04 or later, Debian 12 or
# later) supports this! These are no-ops on earlier versions of libvips.
pyvips.operation_block_set("VipsForeignLoad", True)
pyvips.operation_block_set("VipsForeignLoadHeif", False) # image/avif, image/heic
pyvips.operation_block_set("VipsForeignLoadNsgif", False) # image/gif
pyvips.operation_block_set("VipsForeignLoadJpeg", False) # image/jpeg
pyvips.operation_block_set("VipsForeignLoadPng", False) # image/png
pyvips.operation_block_set("VipsForeignLoadTiff", False) # image/tiff
pyvips.operation_block_set("VipsForeignLoadWebp", False) # image/webp
pyvips.block_untrusted_set(True)
class BadImageError(JsonableError):
code = ErrorCode.BAD_IMAGE

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -10,6 +10,8 @@ import orjson
import pyvips
from django.conf import settings
from django.utils.timezone import now as timezone_now
from pyvips import at_least_libvips
from pyvips import version as libvips_version
from typing_extensions import override
from urllib3 import encode_multipart_formdata
from urllib3.fields import RequestField
@ -1343,11 +1345,16 @@ class AvatarTest(UploadSerializeMixin, ZulipTestCase):
corrupt_files = [
("text.txt", False),
("unsupported.bmp", False),
("actually-a-bmp.png", True),
("corrupt.png", True),
("corrupt.gif", True),
]
for fname, is_valid_image_format in corrupt_files:
with self.subTest(fname=fname):
if not at_least_libvips(8, 13) and "actually-a-" in fname: # nocoverage
self.skipTest(
f"libvips is only version {libvips_version(0)}.{libvips_version(1)}"
)
self.login("hamlet")
with get_test_image_file(fname) as fp:
result = self.client_post("/json/users/me/avatar", {"file": fp})