← Advisories

Memory-safety bugs in libtsm's VTE terminal escape-sequence parser

fixed

Details

Product libtsm
Vendor kmscon
Affected kmscon/libtsm ≤ 4.7.0 (through 8a40f0b; also the Aetf/libtsm fork); fixed in 4.7.1
CWE CWE-125
Severity medium
Status fixed

Timeline

Found 6 Aug 2026
Reported 7 Aug 2026
Fixed 14 Aug 2026
Disclosed 17 Aug 2026

References

Notes

Fuzzing libtsm’s terminal state machine (AFL++ with AddressSanitizer/UBSan) surfaced three memory-safety bugs in the VTE escape-sequence parser, all reachable directly from tsm_vte_input() — i.e. from untrusted terminal output. A terminal built on libtsm (e.g. kmscon) runs a program’s stdout, or a file cat’d to it, straight through this parser, so a crafted byte sequence a few bytes long is enough to reach each bug.

  • Heap out-of-bounds read — cursor backward tab. tsm_screen_tab_left() (src/tsm/tsm-screen.c) indexes tab_ruler[cursor_x - 1] without clamping cursor_x to the screen width, so a cursor-forward-tab (CHT) followed by a wide glyph at the last column and then a cursor-backward-tab (CBT, ESC [ Z) reads past the tab-ruler allocation. (CWE-125.)
  • Out-of-bounds array read — SGR extended color. csi_attribute() (src/tsm/tsm-vte.c) reads csi_argv[i + 1] before checking i + 1 against the parsed argument count, so an SGR sequence whose 38/48 introducer is the sixteenth argument reads one past the fixed int[16] argument array. (CWE-125.)
  • Out-of-bounds read / SIGSEGV — OSC 4 color palette. do_osc_4() parses the colour index as an unbounded unsigned int and passes it to lookup_color(int color); a large value wraps negative, passes the color < 16 test, and wild-reads the palette table in palette_rgb(). The read colour is echoed in the OSC-4 query reply, so a surviving read is also an information leak. (CWE-125.)

Each was reduced to a minimal PoC (11–196 bytes), confirmed on a clean non-AFL ASan/UBSan build, and came with a one-line fix (verified: PoCs clean, no regression on the escape-sequence seed corpus). A follow-up static variant analysis of the three bug classes across the parser found no further siblings — the parser’s bounds handling is otherwise consistent.

The maintainer (Jocelyn Falempe) merged all three patches and released libtsm 4.7.1 on 2026-08-14, crediting the reporter as the commit author. Rebuilding at 4.7.1 and replaying every PoC confirms each parses cleanly under ASan/UBSan.