#1962·stb

[SECURITY] Off-curve point at contour end causes OOB read in stbtt__GetGlyphShapeTT

Author: JerryGWCreated Jun 6, 2026Updated Aug 24, 2026

Summary

Analysis performed with the assistance of AI-based code review tools.

A single off-curve point as the last vertex of a contour causes an out-of-bounds read in stbtt__GetGlyphShapeTT at stb_truetype.h:1780. When the last contour's only point is off-curve, the code reads vertices[off+i+1], which accesses one element past the allocated vertex array.

Environment

  • File: stb_truetype.h
  • Commit: 31c1ad3
  • OS: Linux x86_64
  • Compiler: gcc 15.2.0
  • Test flags: -fsanitize=address -g -O1

Root cause

In stbtt__GetGlyphShapeTT, when a new contour starts with an off-curve point (line 1775: start_off = !(flags & 1)), the code checks the next vertex at line 1780:

if (!(vertices[off+i+1].type & 1)) {

When this off-curve point is the final point in the glyph (i == n-1), off+i+1 evaluates to off+n, indexing one element past the allocated vertex array in this trigger.

The vertex array is allocated at line 1704. This contour's vertices are at indices off through off+n-1; accessing vertices[off+n].type performs a 1-byte read beyond the valid contour data.

Trigger

A crafted TrueType font whose glyph is a single contour containing a single off-curve point. The PoC reads the font from an external file; the TTF is generated by an included Python script (312 bytes, see gen_ttf.py). No real font is required.

Impact

A 1-byte out-of-bounds heap read from an address 12 bytes past the end of the allocated vertex buffer during glyph shape parsing. The crafted font reaches this path through stbtt_GetGlyphShape.

ASAN evidence

=================================================================
==242143==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x78cea81e0046
READ of size 1 at 0x78cea81e0046
    #0 stbtt__GetGlyphShapeTT ../stb_truetype.h:1780
    #1 stbtt_GetGlyphShape ../stb_truetype.h:2303
    #2 main poc_truetype.c:24

0x78cea81e0046 is located 12 bytes after 42-byte region [0x78cea81e0010,0x78cea81e003a)
    allocated by malloc at stb_truetype.h:1704

Full log: see attached verification data.

PoC

Attached: poc_truetype.c, gen_ttf.py

gen_ttf.py poc_truetype.c

Generate the test font and run:

python3 gen_ttf.py
gcc -fsanitize=address -g -O1 poc_truetype.c -o poc_truetype -lm
./poc_truetype font.ttf