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