Skip to content
CVE-2026-95832 ·
Critical · September 25, 2026

Reflected unknown field names in the kitty colour control escape code allow command execution in the user's shell

S0
Secur0 CNA
CVE-2026-95832

Description

Improper Neutralization of Special Elements in Output Used by a Downstream Component (CWE-74) in color_control() (kitty/window.py), in the handler for the colour control escape code, in kitty from 0.47.3 before 0.49.0, which allows a program writing to the terminal to execute an arbitrary command in the user's shell, because the function answers a query for an unrecognised field name by placing that field name into the reply, which write_escape_code_to_child() (kitty/screen.c) then writes to the pseudoterminal master without neutralising it for the shell that reads it. This results in execution of an attacker-chosen command with the privileges of the user running the terminal.

Writing to the pseudoterminal master is not distinguishable from the user typing, so the reflected text lands on the shell's command line. The reflection is the vulnerability.

This is an incomplete fix. Command injection through this handler was addressed in 0.47.3 by commit 424fe999, which reduces the payload to printable ASCII, and that change is the fix for CVE-2026-54057. Its comment records that the restriction exists because the value is echoed back. The restriction does exclude control characters, and the record and field separators ; and = are consumed as delimiters, but every other printable character survives, which is enough to compose a shell command.

The newline that submits the line then has to come from elsewhere, and it is not scarce: handle_remote_ssh() writes the bytes yielded by get_ssh_data() (kittens/ssh/utils.py) straight to the pseudoterminal master, and the first of those bytes begin with a newline, emitted before any credential carried in the request is checked. That handler is reachable without authentication in every release, including v0.49.0.

The reply is framed as an OSC sequence and carries the escape code number, the field name, and the literal value ?, so the attacker chooses a substring of the line rather than the whole of it.

No memory corruption is involved and nothing needs to be groomed or guessed.

The only action required of the victim is that the attacker's text be displayed in a window whose child is a shell at a prompt. Reading a downloaded file, tailing a log that contains attacker-influenced strings, an SSH login banner, the output of a command run against an attacker-controlled host, or a crafted filename shown by a directory listing are all sufficient.

Vulnerability type (CWE)

  • CWE-74: Improper Neutralization of Special Elements in Output Used by a Downstream Component ('Injection')

Affected versions

kitty from 0.47.3 before 0.49.0. The printable ASCII restriction this record concerns is first present in v0.47.3. Every release from v0.47.3 to v0.48.2 inclusive is affected, namely v0.47.3, v0.47.4, v0.48.0, v0.48.1 and v0.48.2. Releases before v0.47.3 reflect the field name with no character restriction and are covered by CVE-2026-54057. Default status: unaffected.

Score (CVSS 4.0)

Critical (9.3)

CVSS:4.0/AV:L/AC:L/AT:N/PR:N/UI:P/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H

The attack vector is Local because kitty reads a pseudoterminal rather than a network socket; arrival over SSH is delivery, not the vector to the vulnerable component. User interaction is Passive because the victim need only display the text. The command runs with the user's privileges, so the impact falls on both the terminal and the subsequent system.

A working exploit for this vulnerability exists.

Solution

Upgrade to kitty 0.49.0 or later.

Patch

Commit 03fbdad8, which reports an unrecognised field as unknown=<base64 encoded field name> rather than placing the field name in the reply, confining the reflected text to a character set from which a shell command cannot be constructed. It also restricts colour numbers and transparent background colour indices to canonical digit strings, so values such as a padded number are treated as unknown fields rather than reflected with their padding, and stops an unhandled exception on a non-numeric index. This commit is the fix: it removes the reflection, which is the attacker's only control over the text.

Commit 57bb144d, in the same release, replaces a digits-only check in handle_remote_echo() that had admitted a trailing newline, because Python's $ also matches immediately before one. That check was itself introduced in v0.48.2 as the fix for CVE-2026-72913, and the handler filtered its payload to printable ASCII in every release before it, so this commit closes a regression in a separate issue and is not the fix for this one. It is cited in the record as a related reference rather than as a patch.

Credits

  • Gabriel Machado Tavares - finder
  • Cristian Fernández Cornejo - analyst
  • Xoán M. Otero Jorge - analyst
  • Secur0 CNA - coordinator
  • Kovid Goyal - remediation developer Discovery source: External

Official record: CVE-2026-95832

Related records

  • CVE-2026-54057 - the earlier command injection in this handler, fixed in 0.47.3 by the restriction this record concerns
  • CVE-2026-72913 - the kitty-echo escape code issue whose fix commit 57bb144d corrects

Related advisories

  • CVE-2026-95834 - Medium severity
  • CVE-2026-95835 - Medium severity