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



CVE-2026-59198

CVE-2026-59198: Heap Out-of-Bounds Read in Pillow TGA RLE Encoder

Alon Barad
Alon Barad
Software Engineer

Jul 21, 2026·8 min read·16 visits

Executive Summary (TL;DR)

A calculation mismatch in Pillow's TGA RLE encoder allows remote attackers to leak up to 57 KB of process heap memory by saving 1-bit images with RLE compression.

CVE-2026-59198 is a high-severity heap out-of-bounds read vulnerability in Pillow, the Python imaging library, affecting versions from 5.2.0 up to 12.3.0. The vulnerability occurs in the TGA RLE compression path due to a calculation mismatch between the allocated packed 1-bit row buffer and the byte-level pixel stride assumption in the C-level encoder. This mismatch allows an attacker to leak up to approximately 57 KB of adjacent process heap memory directly into generated TGA image files.

Vulnerability Overview

The affected component is Pillow's TGA (Truevision Graphics Adapter) image plugin, which manages decoding and encoding operations for TGA-formatted files. Specifically, the vulnerability resides within the Run-Length Encoded (RLE) compression routine. Under standard conditions, applications invoke Pillow to process, transform, and export images, exposing the internal C-based codec libraries to user-supplied input parameters.

The TGA format supports multiple image modes, including 1-bit monochrome (represented as mode "1" in Pillow). When an application saves a mode "1" image using TGA format and specifies RLE compression, control flows from the Python wrapper src/PIL/TgaImagePlugin.py down to the underlying C-extension layer located in src/libImaging/TgaRleEncode.c via the encode.c interface.

The attack surface exists in any application workflow where user-supplied or user-controlled images are saved as TGA files with RLE compression enabled. Since the library fails to validate the compatibility of the bit-packed representation of mode "1" images with the byte-stride assumptions of the RLE encoder, memory layout discrepancies occur during serialization. This leads to a heap-based out-of-bounds read vulnerability, which serializes adjacent process memory directly into the generated output file.

Root Cause Analysis

The root cause of CVE-2026-59198 is a mathematical discrepancy between how Pillow structures bit-packed 1-bit monochrome images in memory and how the TGA RLE encoder reads individual pixel values. In a mode "1" image, Pillow packs 8 monochrome pixels into a single byte of memory to optimize storage efficiency. The initial row buffer allocation size is computed in the C-level encoding controller using the calculation Allocation Size = ((state->bits * state->xsize) + 7) / 8.

When saving a TGA image with a maximum width of 65,535 pixels, the allocation formula evaluates to ((1 * 65535) + 7) / 8 = 8192 bytes. This represents the precise buffer size allocated on the heap to contain the packed 1-bit image data.

However, when RLE compression is enabled, execution transitions to ImagingTgaRleEncode within src/libImaging/TgaRleEncode.c. To iterate through the pixels, the encoder calculates the individual pixel stride using the formula bytesPerPixel = ((state->bits + 7) / 8). Because state->bits is 1 for mode "1" images, integer division rounds this calculation up to 1. Consequently, the encoder assumes that each pixel occupies a full byte rather than a single bit. During iteration, the encoder walks the buffer using an offset of x * bytesPerPixel where x runs up to the full image width of 65,535. This causes the encoder to read up to 65,535 bytes from an 8,192-byte buffer, leading to an out-of-bounds read of approximately 57,343 bytes of adjacent heap memory.

Code Analysis

To understand the flaw and the subsequent correction, examine the vulnerable logical path in the TGA saving routine. The following diagram illustrates the workflow leading to the out-of-bounds read:

The implementation patch blocks the vulnerability at the Python interface level in src/PIL/TgaImagePlugin.py. The patch intercepts the execution path prior to reaching the vulnerable C-extension layer by raising an OSError if a mode "1" image is saved with TGA RLE compression.

Below is the comparison of the vulnerable Python wrapper code versus the patched version:

# === VULNERABLE CODE (Pre-Patch) ===
def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None:
    # ... configuration and header parsing ...
    compression = im.encoderinfo.get("compression", im.info.get("compression"))
    rle = compression == "tga_rle"
    if rle:
        imagetype += 8 # Execution proceeds to C-level RLE encoder with packed bit-buffer
 
# === PATCHED CODE (Post-Patch) ===
def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None:
    # ... configuration and header parsing ...
    compression = im.encoderinfo.get("compression", im.info.get("compression"))
    rle = compression == "tga_rle"
    if rle:
        if im.mode == "1":
            # Prevent the creation of incompatible modes with C-level RLE encoder
            msg = f"cannot write mode {im.mode} as TGA with run-length encoding"
            raise OSError(msg)
 
        imagetype += 8

While this wrapper-level validation successfully prevents exploitation via standard Pillow APIs, it is technically an indirect mitigation. The underlying C function ImagingTgaRleEncode remains unaltered. If external extensions bypass the Python plugin layer and interact directly with the C API using custom packed structures, the underlying memory access discrepancy may still occur. Developers using custom C wrappers for Pillow components must verify that packed images are normalized to 8-bit representation prior to invoking TGA compression.

Exploitation Methodology

Exploiting CVE-2026-59198 does not require specialized authentication or local privileges but is constrained by the application's implementation details. The threat actor must target an application that exposes image uploading and conversion services, allowing the user to dictate the output file format or force TGA RLE processing. The system must also process binary or monochrome images (mode "1") without automatic color-space translation.

An attack scenario proceeds through the following sequential steps:

  1. The attacker uploads a custom-crafted 1-bit monochrome image or forces an existing image to be converted to mode "1".
  2. The attacker triggers the export routine using TGA format with RLE compression enabled (compression="tga_rle").
  3. The backend allocates an 8,192-byte packed buffer for the image row data but invokes the C-level TGA RLE encoder, which processes the memory as if it were 65,535 bytes wide.
  4. The encoder reads approximately 57 KB of memory beyond the allocated row buffer. Since these out-of-bounds bytes are processed by the run-length encoder, they are serialized and written directly into the compressed output data stream of the resulting TGA file.
  5. The attacker downloads the generated TGA image and extracts the raw, uncompressed payload, which contains adjacent process heap memory.

The vulnerability behaves reliably because the C encoder uses deterministic loop bounds. The primary limitation to exploitation is the memory layout adjacent to the image row buffer. If the adjacent memory is unmapped or falls outside the process space, the read will trigger a segmentation fault, causing a denial of service. If the adjacent memory contains active heap data, the data is successfully exfiltrated in the exported file.

Impact Assessment & Threat Intelligence

The primary security consequence of CVE-2026-59198 is unauthorized information disclosure via heap memory exfiltration. Because the heap stores temporary variables, configuration parameters, and buffers from other active application threads, the leaked 57 KB of data may contain sensitive credentials, active session tokens, application keys, or database records. In multi-tenant environments, this leakage could allow one user to intercept the transaction details or credentials of another user processing data concurrently.

Additionally, the leak of heap pointers and internal structural references can bypass Address Space Layout Randomization (ASLR). This provides attackers with the necessary memory layout details to construct subsequent memory corruption exploits. The CVSS v3.1 vector is rated as CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:L with a base score of 6.5. The attack complexity is rated high because it depends on the target application executing a specific image processing flow with specific format parameters.

According to the Exploit Prediction Scoring System (EPSS), the probability of active exploitation in the wild remains low at 0.31% (percentile 23.42%). The vulnerability is not listed in CISA's Known Exploited Vulnerabilities (KEV) catalog, and there are no reports of active exploitation in ransomware campaigns. The overall exploit maturity is limited to proof-of-concept testing.

Remediation & Defensive Guidance

The recommended remediation strategy is upgrading the Pillow installation to version 12.3.0 or higher. This version implements strict input verification at the wrapper layer, raising an OSError and preventing execution from reaching the vulnerable C-based TGA RLE encoder.

In scenarios where immediate package upgrades are unfeasible due to dependency pinning or production freeze windows, developers must implement application-level input sanitization. The following code snippet demonstrates how to intercept and reject vulnerable configurations before saving:

def secure_save(image, output_path, **kwargs):
    # Replicate the patch logic to block the vulnerable path
    format_type = kwargs.get("format", "").upper()
    compression_type = kwargs.get("compression", "")
    
    if format_type == "TGA" and compression_type == "tga_rle":
        if image.mode == "1":
            raise ValueError("Incompatible saving configuration blocked to prevent security risks")
    
    image.save(output_path, **kwargs)

Additionally, security teams should adhere to sandboxing principles for high-risk parsing code. Executing image processing operations within temporary, short-lived containers or restricted namespaces limits the impact of potential information leaks. Restricting the list of permitted image formats and modes via white-lists during file ingest also significantly reduces the available attack surface.

Official Patches

python-pillowOfficial patch removing support for TGA RLE with mode 1 images

Fix Analysis (1)

Technical Appendix

CVSS Score
6.5/ 10
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:L
EPSS Probability
0.31%
Top 77% most exploited

Affected Systems

Pillow (Python Imaging Library)

Affected Versions Detail

Product
Affected Versions
Fixed Version
Pillow
python-pillow
>= 5.2.0, < 12.3.012.3.0
AttributeDetail
CWE IDCWE-125
Attack VectorNetwork
CVSS v3.16.5 (Medium)
EPSS Score0.00313
ImpactInformation Disclosure (Heap Leak up to ~57 KB)
Exploit StatusProof-of-Concept
CISA KEV StatusNot Listed

MITRE ATT&CK Mapping

T1005Data from Local System
Collection
CWE-125
Out-of-bounds Read

The software reads data past the end, or before the beginning, of the intended buffer.

Vulnerability Timeline

Mitigation commit merged into upstream repository
2026-06-22
CVE-2026-59198 officially published and disclosed
2026-07-14
Pillow version 12.3.0 released containing the official patch
2026-07-14

References & Sources

  • [1]Pillow GitHub Security Advisory
  • [2]GitHub Pull Request #9709
  • [3]Official Patch Commit
  • [4]Pillow v12.3.0 Release Notes
  • [5]NVD Vulnerability Details
  • [6]CVE.org Official Record

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.

More Reports

•28 minutes ago•GHSA-RM43-82J9-R4MJ
8.2

GHSA-RM43-82J9-R4MJ: Path Traversal (Arbitrary File Read) in atomic-agents-stack Dashboard

A path traversal vulnerability in the optional dashboard server of atomic-agents-stack before version 1.1.0 allows unauthenticated remote attackers to read arbitrary files from the host filesystem.

Amit Schendel
Amit Schendel
1 views•6 min read
•about 16 hours ago•CVE-2026-9318
5.4

CVE-2026-9318: Stored Cross-Site Scripting via HTML Export in Jazzband tablib

CVE-2026-9318 is a stored cross-site scripting (XSS) vulnerability affecting Jazzband tablib versions prior to 3.10.0. The flaw is located in the HTML export functionality of multi-sheet Databook objects. Due to raw f-string interpolation, unsanitized sheet titles containing malicious script tags are rendered directly as HTML, allowing arbitrary client-side code execution in a victim's browser.

Amit Schendel
Amit Schendel
5 views•8 min read
•about 17 hours ago•CVE-2026-54917
10.0

CVE-2026-54917: Cross-Bucket Path Traversal and Authorization Bypass in SeaweedFS S3 and Iceberg Gateways

CVE-2026-54917 is a critical path traversal and authorization bypass vulnerability affecting the S3 and Iceberg REST catalog gateways in SeaweedFS. By explicitly disabling canonical path cleaning in the gorilla/mux routing system, relative path segments such as '..' are allowed to bypass routing constraints and access control checks. When these paths are collapsed server-side by the backend filer, they resolve to folders outside the authorized bucket boundary, allowing unauthorized cross-bucket access.

Amit Schendel
Amit Schendel
6 views•5 min read
•about 18 hours ago•GHSA-JWJP-4649-V8JP
7.5

GHSA-jwjp-4649-v8jp: Out-of-Bounds Read in SIPSorcery SCTP SACK Chunk Parsing

An out-of-bounds read vulnerability in the SCTP SACK chunk parser of SIPSorcery leads to Denial of Service (DoS) or silent internal state corruption due to lack of boundary validation on incoming chunk elements.

Amit Schendel
Amit Schendel
4 views•6 min read
•about 19 hours ago•GHSA-PFVM-W89X-94JW
7.5

GHSA-pfvm-w89x-94jw: Uncaught Exception in STUN Parser Causes Complete TurnServer Receive Loop Termination

An uncaught exception vulnerability exists in SIPSorcery's TurnServer component, where unauthenticated malformed UDP packets can crash the core UDP receive loop, resulting in a persistent Denial of Service.

Amit Schendel
Amit Schendel
7 views•6 min read
•1 day ago•CVE-2026-62898
7.5

CVE-2026-62898: Use After Free Information Disclosure in Microsoft QUIC

A critical use-after-free vulnerability in Microsoft QUIC allows unauthenticated remote attackers to disclose sensitive system memory over the network. The vulnerability is caused by a race condition during rapid connection termination and asynchronous packet retransmission.

Alon Barad
Alon Barad
14 views•6 min read