GHSA-78g4-xqwv-q3g8 - Pillow: Bundled libopenjp2 2.5.4 in all wheels since 11.1.0 carries OSV-2025-219 heap-buffer-overflow write reachable from Image.open().load()
### Summary
Every Pillow wheel from 11.1.0 onward bundles a libopenjp2 containing a heap-buffer-overflow **write** that is fixed upstream on master but has never appeared in an OpenJPEG release. See https://osv.dev/vulnerability/OSV-2025-219
Because the wheel bundles its own copy, a patched host OS does not help. It is reachable from `Image.open(fp); im.load()` with default settings.
I am reporting it here rather than only upstream because Pillow is where the vulnerable binary actually reaches users.
Note the inversion that makes this easy to miss: **OpenJPEG 2.5.2 and earlier are safe.** The bug was introduced in `954c6e3c` (2024-06-25), so keeping the dependency current is what creates the exposure.
### Details
## Affected wheels
From `.github/dependencies.json` (`openjpeg`) at each tag:
| Pillow | bundled OpenJPEG | status |
|---|---|---|
| 10.4.0 | 2.5.2 | safe |
| 11.0.0 | 2.5.2 | safe |
| **11.1.0, 11.2.1, 11.3.0** | **2.5.3** | **affected** |
| **12.0.0 โฆ 12.3.0** | **2.5.4** | **affected** |
Confirmed on an installed wheel: `PIL.features.version_codec('jpg_2000')` โ `2.5.4`, bundled file `pillow.libs/libopenjp2-*.so.2.5.4`. `main` still pins `2.5.4` as of 2026-10-06.
## The defect
`src/lib/openjp2/j2k.c`, in `opj_j2k_read_sod`:
```c
OPJ_UINT32 l_current_tile_part =
l_cstr_index->tile_index[p_j2k->m_current_tile_number].current_tpsno;
l_cstr_index->tile_index[...].tp_index[l_current_tile_part].end_header = l_current_pos;
l_cstr_index->tile_index[...].tp_index[l_current_tile_part].end_pos =
l_current_pos + p_j2k->m_specific_param.m_decoder.m_sot_length + 2;
```
`tp_index` is neither null-checked nor bounds-checked, and `l_current_tile_part` comes directly from the one-byte `TPsot` field of the SOT marker.
The correct guard already exists a few lines later in `opj_j2k_add_tlmarker` (j2k.c:8459), writing the **same array at the same index** behind `if (tp_index && l_current_tile_part < nb_tps)`. One writer checked, its sibling not.
Reach
HIGH
Severity & confidence
Source severityhigh
Platform severityhigh
Confidencemedium
Exploitationunknown
CVSS8.1
Affected
Vendorspillow
Productspillow
Reporting sources (1)
GitHub Security Advisories
Timeline & provenance
Published2026-10-22T17:01:08
Last updated2026-10-25T02:26:17
Ingested2026-10-22T17:11:25
FreshnessNEAR-REAL-TIME
Threat typeadvisory
Recommended action
Review the advisory and upgrade affected packages to the first patched version.
Next steps
- Identify affected systems in your environment.
- Apply the vendor patch or mitigation guidance.
- Review logs for indicators described in the advisory.
- Follow the affected vendor/product to track updates.
Confidence explanation
Reported by a single or secondary source; treat as indicative, verify before acting.
Source type: vendor ยท Original: GitHub Security Advisories