#1149729 kitty: CVE-2026-80430 CVE-2026-80431 CVE-2026-80432 CVE-2026-95832 CVE-2026-95834 CVE-2026-95835

Package:
src:kitty
Source:
src:kitty
Submitter:
Salvatore Bonaccorso
Date:
2026-10-02 18:53:02 UTC
Severity:
normal
Tags:
#1149729#5
Date:
2026-10-02 18:50:29 UTC
From:
To:
Hi,

The following vulnerabilities were published for kitty.

CVE-2026-80430[0]:
| Improper Link Resolution Before File Access in the drag source
| staging path of the drag and drop protocol in kitty from 0.47.0
| before 0.49.0 allows a program writing to the terminal to create
| files and directories at paths outside the staging directory,
| because subdir_data_for_drag() in kitty/dnd.c resolves a descendant
| of the staged item tree by constructing a path string and opening it
| with safe_open(path, O_DIRECTORY | O_RDONLY, 0) rather than by
| walking the tree one component at a time, so a client that declares
| two entries with the same name, the first a symlink whose target is
| an arbitrary absolute path and the second a directory, causes
| mkdirat() to fail with EEXIST, which the code ignores, and causes
| the subsequent path resolution to follow the symlink and return a
| directory descriptor outside the staging directory, which is then
| passed as the dirfd argument to add_payload() and used for every
| further create operation on that item and its descendants. Entry
| names are sanitised against path separators and dot components, but
| symlink targets are not validated. Files are created with O_CREAT |
| O_WRONLY | O_EXCL at mode 0644, so existing files cannot be
| overwritten, and directories are created with mkdirat() at mode
| 0755, so the attacker can create intermediate directories that did
| not previously exist. This results in the creation of files and
| directories at any path writable by the user running kitty, provided
| the symlink target is an existing directory.


CVE-2026-80431[1]:
| Out-of-bounds Write in the natural width branch of the text sizing
| protocol in kitty from 0.40.0 before 0.49.0 allows a program writing
| to the terminal to write past the end of a fixed-size buffer,
| because screen_handle_multicell_command() in kitty/screen.c appends
| each codepoint of a grapheme cluster with lc.chars[lc.count++] = ch
| without any capacity check, while lc is declared by the
| RAII_ListOfChars macro as a four-element char_type array in the
| function's stack frame, so an OSC 66 escape code whose payload
| carries a grapheme cluster longer than four codepoints writes beyond
| that buffer, one 32-bit value per additional codepoint, in the order
| the codepoints appear. Where the cluster is preceded in the same
| payload by a sequence that causes an intermediate flush, the buffer
| is first migrated to the heap by ensure_space_for_chars() and the
| write occurs past the heap allocation instead. This results in
| termination of the kitty process and therefore of all its windows,
| tabs and child processes.


CVE-2026-80432[2]:
| Missing Authorization in the drop handling path of the drag and drop
| protocol in kitty from 0.47.0 before 0.49.0 allows a program writing
| to the terminal to obtain the contents of files dragged over the
| window even when the user never completes the drop, because
| drop_enqueue_request() in kitty/dnd.c serves a drag data request
| without first checking the drop state of the window, so a client
| that issues the request while a drag is merely hovering receives the
| data offered for the drag. In the same file, drop_left_child(),
| which runs when the drag leaves the window without a drop having
| occurred, releases the offered MIME list but retains the pending
| request state, the open file descriptor and its main loop transfer
| timer, the directory handles, the URI list and the pending MIME
| name, so a client can continue to read through a retained directory
| handle, and an in-flight file transfer continues to stream, when no
| drag is in progress. The file contents are read from the filesystem
| by the kitty process itself using the paths the drag source offered.
| This results in disclosure of the contents of files the user moved
| over the window without ever releasing them into it.


CVE-2026-95832[3]:
| Improper Neutralization of Special Elements in Output Used by a
| Downstream Component in the colour control escape code handler in
| kitty from 0.47.3 before 0.49.0 allows a program writing to the
| terminal to execute an arbitrary command in the user's shell,
| because color_control() in kitty/window.py answers a query for an
| unrecognised field name by placing that field name into the reply,
| and write_escape_code_to_child() in kitty/screen.c then writes the
| reply to the pseudoterminal master, where it is not distinguishable
| from input typed by the user, without neutralising it for the shell
| that reads it. The payload is reduced to printable ASCII before the
| field name is echoed, which is the restriction introduced in 0.47.3
| as the fix for CVE-2026-54057, and the record and field separators ;
| and = are consumed as delimiters, but every other printable
| character survives, which is sufficient to compose a shell command.
| A newline is available from handle_remote_ssh() in kitty/window.py,
| which writes the bytes yielded by get_ssh_data() in
| kittens/ssh/utils.py, the first of which begin with a newline, to
| the pseudoterminal master before any credential carried in the
| request is checked. The reply is framed as an OSC sequence carrying
| the escape code number, the field name, and the literal value ?.
| This results in execution of an attacker-chosen command with the
| privileges of the user running the terminal.


CVE-2026-95834[4]:
| Use After Free in the drag source path of the drag and drop protocol
| in kitty from 0.47.0 before 0.49.0 allows a program writing to the
| terminal to cause the terminal to read from and write to freed heap
| memory, because drag_remote_file_data() in kitty/dnd.c holds a
| DragRemoteItem pointer into an array it does not own, calls
| toplevel_data_for_drag() or subdir_data_for_drag(), and then
| continues to use that pointer. Those helpers, and add_payload() and
| populate_dir_entries() which they call, report errors through the
| abrt() macro, which expands to cancel_drag() followed by a plain
| return, and cancel_drag() calls drag_free_offer(), which frees the
| array the pointer refers to. The helpers return void, so the caller
| receives no indication that the teardown happened, and proceeds to
| call all_children_complete() on the freed pointer, which
| dereferences it, and then to write through it. That dereference is
| guarded by a local flag that is set when the request carries no
| payload and announces no further data, which is the same condition
| that selects the finalisation block of add_payload(), so the error
| paths in that block reach it: a create that fails because an entry
| of the same name already exists, because the client may declare two
| entries with one name and the create operations use O_CREAT with
| O_EXCL and symlinkat(), a mkdirat() failure other than EEXIST, and
| the directory entry allocation paths. Both branches reach it. In the
| top level branch the caller's pointer is never cleared, so clearing
| the owning structure's own pointers during teardown does not help.
| In the sub directory branch subdir_data_for_drag() sets the caller's
| pointer to NULL on entry and assigns it only after its own last
| error path, so its own aborts leave the caller with NULL and are
| stopped by a null check, but it then calls add_payload() with that
| pointer set, and an abort there leaves the caller holding a freed
| child node inside the item tree, which drag_free_offer() frees by
| recursion. This results in undefined behaviour in the terminal
| process, reachable from the byte stream of any program running in
| the window.


CVE-2026-95835[5]:
| Missing Authorization in the askpass escape code handler in kitty
| from 0.25.0 before 0.49.0 allows a local user other than the one
| running the terminal to obtain the text typed into a prompt that
| kitty itself displays, because handle_remote_askpass() in
| kitty/window.py opens the POSIX shared memory object named in the
| escape code, parses a prompt definition out of it, and writes the
| user's answer back into an object of that same name, without at any
| point checking that the object is owned by the user running kitty or
| that its permissions exclude other users. The equivalent consumer of
| the same SharedMemory class in the ssh kitten performs exactly that
| check; the askpass path did not. The handler is reached through a
| device control string processed from the byte stream of the window,
| so the attacker must also cause bytes of their choosing to be
| displayed by the victim's terminal. Where the POSIX shared memory
| namespace is shared between the two users, a second local user can
| create an object with permissions that allow the victim to read and
| write it, cause the victim's kitty to render a prompt of the
| attacker's choosing, including a masked password prompt, and read
| the typed secret back out of the object afterwards. The prompt text
| is additionally passed to the display without control character
| sanitisation, so it can overwrite the warning line kitty prints
| above it. The answer is written by reopening an object of that name
| when the user answers, rather than through the handle already held.
| This results in disclosure of a secret typed by the victim to a
| second local user, and does not require any privilege on the
| victim's account.


If you fix the vulnerabilities please also make sure to include the
CVE (Common Vulnerabilities & Exposures) ids in your changelog entry.

For further information see:

[0] https://security-tracker.debian.org/tracker/CVE-2026-80430
https://www.cve.org/CVERecord?id=CVE-2026-80430
[1] https://security-tracker.debian.org/tracker/CVE-2026-80431
https://www.cve.org/CVERecord?id=CVE-2026-80431
[2] https://security-tracker.debian.org/tracker/CVE-2026-80432
https://www.cve.org/CVERecord?id=CVE-2026-80432
[3] https://security-tracker.debian.org/tracker/CVE-2026-95832
https://www.cve.org/CVERecord?id=CVE-2026-95832
[4] https://security-tracker.debian.org/tracker/CVE-2026-95834
https://www.cve.org/CVERecord?id=CVE-2026-95834
[5] https://security-tracker.debian.org/tracker/CVE-2026-95835
https://www.cve.org/CVERecord?id=CVE-2026-95835
Regards,
Salvatore