To The Security Team at WikiMedia:
I'm unfortunately the bearer of bad news. It appears that MediaWiki is indirectly vulnerable to CVE-2023-21036. This bug, also known as "aCropalypse", relates to how Google Pixel phones handle image processing, modification and cropping. The full details are linked below [1], but to make a long story short, any image that hasn't been post processed can have redactions, and crops removed. Needless to say, this is rather concerning for any site with a large number of images.
In my testing, using Special:Upload and Special:UploadWizard both retain the uploaded image exactly as is. This isn't surprising since MediaWiki makes the original uploaded file available, including any embedded metadata. However, I believe that given the possibility of unintentional upload and release of private and personal information (PPI), this needs to be handled in some fashion, even if it's a tool that can automatically update and remove any trailing garbage data in the PNG file.
This problem can occur with any file upload, but I personally reproduced on my own wiki at wiki.restless.systems which you can see here: https://wiki.restless.systems/wiki/File:Sc-2test.png
The full version information is available on Special:Version [2], but it's a MediaWiki 1.38.2 install, running PHP 7.4.30, and Upload Wizard 1.5.0 (rECIRde677a71a856). By using a test script, I can confirm that the image server side is still vulnerable, as is the one I downloaded from my browser.
While I'm not certain how best to resolve this for the massive number of images on various Wikipedia sites, it would be possible to "fix" vulnerable images by simply parsing the PNG files, and then deleting all the data past the IEND tag, which marks the actual end of image. While this would change the file hash, it would remove all data that shouldn't be there.
I'm available to help in any way possible,
Michael Casadevall
Restless Systems LLC
[1] https://www.da.vidbuchanan.co.uk/blog/exploiting-acropalypse.html
[2] https://wiki.restless.systems/wiki/Special:Version
#!/usr/bin/python3 import zlib import sys import io PNG_MAGIC = b'\x89PNG\r\n\x1a\n' def parse_png_chunk(stream): size = int.from_bytes(stream.read(4), "big") ctype = stream.read(4) body = stream.read(size) csum = int.from_bytes(stream.read(4), "big") assert(zlib.crc32(ctype + body) == csum) return ctype, body def pack_png_chunk(stream, name, body): stream.write(len(body).to_bytes(4, "big")) stream.write(name) stream.write(body) crc = zlib.crc32(body, zlib.crc32(name)) stream.write(crc.to_bytes(4, "big")) png_f = open(sys.argv[1], "rb") magic = png_f.read(len(PNG_MAGIC)) if magic != PNG_MAGIC: print("not a png file") sys.exit(-1) # scan to end of the PNG while True: chunk_type, chunk_body = parse_png_chunk(png_f) if chunk_type == b"IEND": break trailing_data = png_f.read() if len(trailing_data) > 0: print("png is vulnerable") sys.exit(-2) else: #print("png is safe!") sys.exit(0)