RUSTSEC-2026-0430
Path traversal in `rio-vt` Kitty graphics protocol handler allows out-of-bounds file delete (and read)
The Kitty graphics protocol handler in rio-vt builds a filesystem path from an attacker-controlled APC escape sequence and, for the temp-file medium, only checks that the path contains the substring "tty-graphics-protocol" before it opens, reads, and remove_files it. There is no .. rejection and no canonicalization, so a path containing the marker substring plus .. escapes the terminal's temp directory (path traversal, CWE-22/CWE-23).
Because a terminal renders whatever arrives on the PTY (ssh output, a cat'd file, CI logs), untrusted output can delete a file outside the temp area and cause its bytes to be read back in.
Details
The sink is create_graphic_data() in src/ansi/kitty_graphics_protocol.rs, in the TransmissionMedium::TempFile branch, reachable through the public API rio_vt::ansi::kitty_graphics_protocol::parse. The path is the base64 APC payload of an a=t,t=t command, and the guard is:
let path = Path::new(path_str);
if !path.is_file() { return Err(GraphicError::FileNotFound); } // literal path, resolves `..`
// reject /proc/ /sys/ /dev/ (lowercased substring)
if cmd.medium == TransmissionMedium::TempFile
&& !path_str.contains("tty-graphics-protocol") { // SUBSTRING, not a component
return Err(GraphicError::InvalidData);
}
// ...
let mut file = File::open(path)...; // reads file bytes
if cmd.medium == TransmissionMedium::TempFile {
let _ = std::fs::remove_file(path); // deletes the file
}
This affects any terminal emulator or application built on rio-vt (e.g. the Rio terminal) that renders attacker-influenced output: an out-of-bounds file is deleted, and its contents are read into the process.
The fix
Fixed in rio-vt 0.5.29 (Rio 0.5.29) by PR #1998. For the temp-file medium the parent directory is resolved with canonicalize before any check, the resolved entry must lie inside a temp directory (temp_dir(), /tmp or /dev/shm) and contain the marker, and the delete goes through unlinkat on a handle to the validated directory, so neither .. nor a swapped symlink can redirect it. Path checks for the file medium also run on the file actually opened.
Attack profile
How easy it is to exploit
- Attack vector
- Local
- Complexity
- High
- Privileges needed
- None
- User interaction
- Required
What an attacker can affect
- Confidentiality
- None
- Integrity
- High
- Availability
- None
What each source reports
OSV Score used
4.7
Path traversal in `rio-vt` Kitty graphics protocol handler allows out-of-bounds file delete (and read)
The Kitty graphics protocol handler in rio-vt builds a filesystem path from an attacker-controlled APC escape sequence and, for the temp-file medium, only checks that the path contains the substring "tty-graphics-protocol" before it opens, reads, and remove_files it. There is no .. rejection and no canonicalization, so a path containing the marker substring plus .. escapes the terminal's temp directory (path traversal, CWE-22/CWE-23).
Because a terminal renders whatever arrives on the PTY (ssh output, a cat'd file, CI logs), untrusted output can delete a file outside the temp area and cause its bytes to be read back in.
Details
The sink is create_graphic_data() in src/ansi/kitty_graphics_protocol.rs, in the TransmissionMedium::TempFile branch, reachable through the public API rio_vt::ansi::kitty_graphics_protocol::parse. The path is the base64 APC payload of an a=t,t=t command, and the guard is:
let path = Path::new(path_str);
if !path.is_file() { return Err(GraphicError::FileNotFound); } // literal path, resolves `..`
// reject /proc/ /sys/ /dev/ (lowercased substring)
if cmd.medium == TransmissionMedium::TempFile
&& !path_str.contains("tty-graphics-protocol") { // SUBSTRING, not a component
return Err(GraphicError::InvalidData);
}
// ...
let mut file = File::open(path)...; // reads file bytes
if cmd.medium == TransmissionMedium::TempFile {
let _ = std::fs::remove_file(path); // deletes the file
}
This affects any terminal emulator or application built on rio-vt (e.g. the Rio terminal) that renders attacker-influenced output: an out-of-bounds file is deleted, and its contents are read into the process.
The fix
Fixed in rio-vt 0.5.29 (Rio 0.5.29) by PR #1998. For the temp-file medium the parent directory is resolved with canonicalize before any check, the resolved entry must lie inside a temp directory (temp_dir(), /tmp or /dev/shm) and contain the marker, and the delete goes through unlinkat on a handle to the validated directory, so neither .. nor a swapped symlink can redirect it. Path checks for the file medium also run on the file actually opened.
- Record
RUSTSEC-2026-0430- CVSS 3.1
- 4.7 Medium
CVSS:3.1/AV:L/AC:H/PR:N/UI:R/S:U/C:N/I:H/A:N - Updated
- 2026-11-02
Affected packages
| Package | Affected | Fixed |
|---|---|---|
rio-vtcrates.io |
0.0.0-0 up to 0.5.29 | 0.5.29 |
History
| Recorded | Changed | Sources |
|---|---|---|
| first indexed | OSV |
Dates are when Every CVE recorded each change. Upstream dates may differ.
In short
RUSTSEC-2026-0430 is a medium vulnerability (CVSS 4.7) in rio-vt, published November 1, 2026. No source lists public exploit code. Fixed in rio-vt 0.5.29.