getgrav/grav: Anonymous visitors can bypass the image pixel limit when image URL actions are enabled
What fixes it
- 2.2.2getgrav/grav, composerGitHub
composer require "getgrav/grav:^2.2.2" - 1.7.53.5getgrav/grav, composerGitHub
composer require "getgrav/grav:^1.7.53.5"
A fixed version on one release line is not the upgrade target for every line. Check your exact version and any vendor backports.
Description
Summary
When system.images.url_actions is enabled, the system.images.max_pixels limit only checked the width and height written in the query string, and only when both were present. A resize given one dimension or a percentage (image.jpg?forceResize=46000, ?forceResize=4600%), a zoomCrop whose box is small but whose intermediate canvas is not (?zoomCrop=46000,1), or a chain of actions all passed the check. That let an anonymous visitor make GD allocate a canvas of up to about 2 billion pixels (roughly 8.6 GB) per request.
Affected versions
Grav 2.0.0-rc.8 through 2.2.1, and 1.7.53 through 1.7.53.4, on sites that have turned on system.images.url_actions. It is off by default, but the migrate-grav plugin turns it on for migrated sites whose content uses query-string image transforms.
Details
Grav::fallbackUrl() rejected a resize only when width > 0 && height > 0 && width * height > max_pixels. The image library derives a missing dimension from the source aspect ratio, resolves percentages against the source, and zoomCrop() enlarges to cover the requested box before cropping, so the canvas it allocates can be far larger than the query numbers. On PHP builds that link the system libgd, this memory is allocated outside PHP's memory_limit. Derivatives are cached, but every new size is a cache miss, and a failed allocation is never cached.
The original report described a forceResize=1000000 payload. GD refuses that size outright; the working range tops out around 46000 per side, and the percentage and zoomCrop variants reach the same size.
Impact
An unauthenticated visitor can exhaust memory on the web server with one short request per worker, taking the site down and, without per-pool memory limits, affecting other processes on the host.
Patches
Fixed in Grav 2.2.2 and 1.7.53.5. The limit now measures the canvas each URL action actually allocates, including derived dimensions, percentages, zoomCrop's intermediate canvas and chained actions. As a workaround, turn system.images.url_actions off.
Credits
Reported by @manus-pi.
Text from GitHub Advisory Database
Affected versions 2
- getgrav/grav, composer>= 2.0.0-rc.8, < 2.2.2GitHub
- getgrav/grav, composer>= 1.7.53, < 1.7.53.5GitHub