CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



GHSA-78G4-XQWV-Q3G8

GHSA-78G4-XQWV-Q3G8: Heap-Based Buffer Overflow in Pillow (libopenjp2)

Alon Barad
Alon Barad
Software Engineer

Oct 23, 2026·4 min read·2 visits

Executive Summary (TL;DR)

Heap buffer overflow write in bundled libopenjp2 during JPEG 2000 parsing in Pillow releases >= 11.1.0. Fixed in Pillow 13.0.0.

A heap-based buffer overflow vulnerability in Pillow PyPI binary wheels (versions 11.1.0 to 12.x) allows remote code execution or application crash via crafted JPEG 2000 files processed by the bundled libopenjp2 library.

Vulnerability Overview

Security advisory GHSA-78G4-XQWV-Q3G8 details a high-severity heap-based buffer overflow flaw in the Python Imaging Library (Pillow). The flaw originates in the bundled open-source JPEG 2000 codec library, libopenjp2, which is statically linked or packaged within official PyPI pre-compiled binary wheels starting with Pillow version 11.1.0.

When Pillow processes a crafted JPEG 2000 image, the underlying libopenjp2 library fails to validate the index boundaries of a tile-part array before attempting to write metadata into memory. This missing boundary check leads to an out-of-bounds write of 8 bytes on the process heap (Heap-buffer-overflow WRITE 8).

The vulnerability is tracked upstream as OSV-2025-219 and was initially discovered via Google OSS-Fuzz Issue 403673832. Because the affected functionality is accessible through standard image loading methods such as Image.open().load(), any application accepting user-supplied JPEG 2000 images is vulnerable to process memory corruption.

Root Cause Analysis

The root cause resides within src/lib/openjp2/j2k.c in the opj_j2k_read_sod function, which processes the Start of Data (SOD) marker in JPEG 2000 codestreams. The parser extracts the current tile-part index (l_current_tile_part) from the tile's tracking structure using l_cstr_index->tile_index[p_j2k->m_current_tile_number].current_tpsno.

During codestream processing, current_tpsno is derived directly from parameters present in preceding TPsot markers in the attacker-controlled image file. In vulnerable releases of libopenjp2 (versions 2.5.3 and 2.5.4), the parser immediately wrote end_header and end_pos values into the tp_index array using l_current_tile_part as the direct array index.

The library failed to verify two critical safety conditions before executing the memory write: first, whether tp_index was properly allocated (non-NULL); second, whether l_current_tile_part was strictly less than nb_tps (the maximum allocated tile-parts capacity). As a consequence, providing an arbitrarily large or invalid tile-part index allows an attacker to corrupt heap memory past the end of the allocated array.

Code Analysis

The vulnerable code path within src/lib/openjp2/j2k.c attempts direct array assignments without checking array bounds or pointer validity.

// Vulnerable Code Path in OpenJPEG 2.5.4 (src/lib/openjp2/j2k.c)
OPJ_UINT32 l_current_tile_part =
    l_cstr_index->tile_index[p_j2k->m_current_tile_number].current_tpsno;
 
// Missing bounds validation on l_current_tile_part before access
l_cstr_index->tile_index[p_j2k->m_current_tile_number].tp_index[l_current_tile_part].end_header
    = l_current_pos;
l_cstr_index->tile_index[p_j2k->m_current_tile_number].tp_index[l_current_tile_part].end_pos
    = l_current_pos + p_j2k->m_specific_param.m_decoder.m_sot_length + 2;

The upstream fix introduced in OpenJPEG commit 91d08b11a72764f6d199f32fa0c1b1abd4edc2ad adds an explicit guard check confirming tp_index is non-NULL and l_current_tile_part remains within the allocated nb_tps bounds.

// Patched Code Path in OpenJPEG (src/lib/openjp2/j2k.c)
OPJ_UINT32 l_current_tile_part =
    l_cstr_index->tile_index[p_j2k->m_current_tile_number].current_tpsno;
 
// Added guard checks for non-NULL tp_index and index bounds verification
if (l_cstr_index->tile_index[p_j2k->m_current_tile_number].tp_index &&
        l_current_tile_part <
        l_cstr_index->tile_index[p_j2k->m_current_tile_number].nb_tps) {
    l_cstr_index->tile_index[p_j2k->m_current_tile_number].tp_index[l_current_tile_part].end_header
        = l_current_pos;
    l_cstr_index->tile_index[p_j2k->m_current_tile_number].tp_index[l_current_tile_part].end_pos
        = l_current_pos + p_j2k->m_specific_param.m_decoder.m_sot_length + 2;
}

Pillow integrated this patch into its build scripts via commits 5f8114c8096b181fae493543cd3837d9f9a971cc and d3470c327840f4c216a1610f30e7091dfd0b97c0, ensuring that the compiled binary wheels bundle patched library sources.

Exploitation Methodology

Exploitation requires supplying a specially structured JPEG 2000 file (.jp2 or .j2k) to an application that processes images using Python Pillow. No authentication is required if the target application processes user-uploaded files or remote images.

The attack vector triggers when the application invokes image loading operations that invoke the underlying native library decoder:

from PIL import Image
 
# Opening and loading a crafted JPEG 2000 image triggers opj_j2k_decode
im = Image.open("malicious.jp2")
im.load()  # Invokes C-level decoder: opj_j2k_decode -> opj_j2k_read_sod

When opj_j2k_read_sod processes the Start of Data marker, the out-of-bounds write occurs. An attacker controlling the value of l_current_pos can write 8-byte integers past the boundaries of the allocated heap chunk. While public exploits currently demonstrate denial-of-service through memory corruption crashes, carefully aligned heap grooming could allow arbitrary memory overwrites.

Impact Assessment

The impact of this vulnerability ranges from application crash (Denial of Service) to arbitrary code execution within the security context of the Python runtime process. Process termination occurs immediately when address sanitizers or heap integrity checks detect the out-of-bounds write.

Applications running automated image transformation pipelines, web application file upload endpoints, or asynchronous background tasks (such as Celery workers) are directly exposed if they accept JPEG 2000 format inputs.

Because pre-compiled PyPI wheel distributions bundle libopenjp2 directly, environments relying strictly on standard pip install pillow without platform-level package management inherit this flaw automatically.

Remediation Guidance

To remediate GHSA-78G4-XQWV-Q3G8, upgrade Pillow to version 13.0.0 or higher. PyPI wheels for Pillow 13.0.0 contain updated and patched versions of libopenjp2.

pip install --upgrade "pillow>=13.0.0"

If Pillow is built from source using system libraries, ensure the host system's libopenjp2 library package contains OpenJPEG commit 91d08b11a72764f6d199f32fa0c1b1abd4edc2ad or update to OpenJPEG version 2.5.5 or later.

If immediate upgrading is not feasible, restrict application input validation rules to block JPEG 2000 image extensions (.jp2, .j2k, .jpf) before calling Pillow parsing functions.

Fix Analysis (3)

Technical Appendix

CVSS Score
7.5/ 10

Affected Systems

Python Pillow PyPI Wheel Packages (11.1.0 to 12.x)OpenJPEG libopenjp2 (2.5.3, 2.5.4)

Affected Versions Detail

Product
Affected Versions
Fixed Version
Pillow (PyPI Wheels)
Python Pillow
>= 11.1.0, < 13.0.013.0.0
libopenjp2 (OpenJPEG)
OpenJPEG
2.5.3 - 2.5.42.5.5
AttributeDetail
CWE IDCWE-122 (Heap-based Buffer Overflow)
Attack VectorNetwork / Remote (Malicious JPEG 2000 file upload)
CVSS Score7.5 (High)
EPSS ScoreN/A (No CVE assigned)
ImpactMemory Corruption / Remote Code Execution / Denial of Service
Exploit StatusProof of Concept / OSS-Fuzz Crash Test Case
CISA KEV StatusNot Listed

MITRE ATT&CK Mapping

T1203Exploitation for Client Execution
Execution
T1190Exploit Public-Facing Application
Initial Access
CWE-122
Heap-based Buffer Overflow

Vulnerability Timeline

OSS-Fuzz discovers heap overflow issue 403673832 in OpenJPEG
2025-01-08
OpenJPEG upstream repository publishes fix commit 91d08b11a72764f6d199f32fa0c1b1abd4edc2ad
2025-01-10
Pillow repository integrates patch into wheel build systems
2025-01-15
Pillow 13.0.0 released with patched libopenjp2 dependencies
2025-01-20

References & Sources

  • [1]GitHub Security Advisory GHSA-78G4-XQWV-Q3G8
  • [2]OSV Vulnerability Record OSV-2025-219
  • [3]OSS-Fuzz Issue 403673832 Report
  • [4]OpenJPEG Upstream Fix Commit
  • [5]Pillow Fix Commit 1
  • [6]Pillow Fix Commit 2
  • [7]Pillow Release 13.0.0 Tag

More Reports

•about 1 hour ago•CVE-2026-109618
9.8

CVE-2026-109618: Remote Code Execution in PHP Core via Out-of-Memory longjmp() Uninitialized Memory Access

CVE-2026-109618 (dubbed PHP2Shell) is a critical vulnerability in the PHP engine core resulting from improper out-of-memory exception handling via longjmp(). When request allocation fails mid-processing, non-local control flow bypasses cleanup procedures, leaving memory structures uninitialized or in a use-after-free state during request shutdown.

Amit Schendel
Amit Schendel
9 views•5 min read
•about 1 hour ago•CVE-2026-109619
9.2

CVE-2026-109619: Remote Code Execution in PHP Core via Stale Global State Memory Corruption (PHP2Shell)

CVE-2026-109619 (PHP2Shell) is a critical Use-After-Free vulnerability in the core PHP engine caused by improper global state cleanup during out-of-memory exception handling across persistent worker requests.

Alon Barad
Alon Barad
10 views•6 min read
•about 1 hour ago•CVE-2026-113721
4.5

CVE-2026-113721: Unsafe Link Resolution in virtualenv File Generation

In Python virtualenv prior to version 21.14.9, activation script generators and configuration writers use Path.exists() before writing files. Because Path.exists() resolves symbolic links, it returns False for dangling symlinks. Consequently, virtualenv skips unlinking pre-planted symbolic links or hard links, writing data directly to target locations outside the intended virtual environment directory.

Amit Schendel
Amit Schendel
3 views•5 min read
•9 days ago•CVE-2026-87697
8.8

CVE-2026-87697: Untrusted Deserialization in .NET PresentationCore Clipboard Handling

A remote code execution vulnerability exists in Microsoft .NET due to untrusted data deserialization within the PresentationCore component. The flaw stems from implicit auto-conversion flags during clipboard data retrieval operations.

Alon Barad
Alon Barad
31 views•5 min read
•10 days ago•CVE-2026-70007
8.8

CVE-2026-70007: Out-of-Bounds Write Vulnerability in .NET Framework and WPF Subsystem

An out-of-bounds write vulnerability in Microsoft .NET Framework, .NET runtime, and Visual Studio allows unauthenticated remote attackers to execute arbitrary code via crafted pixel-shader bytecode or auto-converted clipboard payloads.

Amit Schendel
Amit Schendel
19 views•6 min read
•10 days ago•CVE-2026-70186
7.5

CVE-2026-70186: ASP.NET Core Denial of Service Vulnerability via Framework Deadlock

ASP.NET Core contains a thread deadlock vulnerability (CWE-833) that allows an unauthenticated remote attacker to cause a denial of service over the network by exhausting server thread pool resources.

Amit Schendel
Amit Schendel
18 views•5 min read