RUSTSEC-2026-0430
Vulnerability from osv_rustsec – Published: 2026-11-01 12:00 – Updated: 2026-11-02 10:46 – Source websiteThe 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.
{
"affected": [
{
"database_specific": {
"categories": [
"file-disclosure"
],
"cvss": "CVSS:3.1/AV:L/AC:H/PR:N/UI:R/S:U/C:N/I:H/A:N",
"informational": null
},
"ecosystem_specific": {
"affected_functions": null,
"affects": {
"arch": [],
"functions": [
"rio_vt::ansi::kitty_graphics_protocol::parse"
],
"os": []
}
},
"package": {
"ecosystem": "crates.io",
"name": "rio-vt",
"purl": "pkg:cargo/rio-vt"
},
"ranges": [
{
"events": [
{
"introduced": "0.0.0-0"
},
{
"fixed": "0.5.29"
}
],
"type": "SEMVER"
}
],
"versions": []
}
],
"aliases": [],
"database_specific": {
"license": "CC0-1.0"
},
"details": "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_file`s it. There is no `..` rejection and no canonicalization, so a path containing the marker substring plus `..` escapes the terminal\u0027s temp directory (path traversal, CWE-22/CWE-23).\n\nBecause a terminal renders whatever arrives on the PTY (ssh output, a `cat`\u0027d file, CI logs), untrusted output can delete a file outside the temp area and cause its bytes to be read back in.\n\n## Details\n\nThe 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:\n\n```rust\nlet path = Path::new(path_str);\nif !path.is_file() { return Err(GraphicError::FileNotFound); } // literal path, resolves `..`\n// reject /proc/ /sys/ /dev/ (lowercased substring)\nif cmd.medium == TransmissionMedium::TempFile\n \u0026\u0026 !path_str.contains(\"tty-graphics-protocol\") { // SUBSTRING, not a component\n return Err(GraphicError::InvalidData);\n}\n// ...\nlet mut file = File::open(path)...; // reads file bytes\nif cmd.medium == TransmissionMedium::TempFile {\n let _ = std::fs::remove_file(path); // deletes the file\n}\n```\n\nThis 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.\n\n## The fix\n\nFixed in `rio-vt` 0.5.29 (Rio 0.5.29) by [PR #1998](https://github.com/raphamorim/rio/pull/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.",
"id": "RUSTSEC-2026-0430",
"modified": "2026-11-02T10:46:59Z",
"published": "2026-11-01T12:00:00Z",
"references": [
{
"type": "PACKAGE",
"url": "https://crates.io/crates/rio-vt"
},
{
"type": "ADVISORY",
"url": "https://rustsec.org/advisories/RUSTSEC-2026-0430.html"
},
{
"type": "ADVISORY",
"url": "https://github.com/raphamorim/rio/security/advisories/GHSA-m926-9wrf-jr8w"
},
{
"type": "WEB",
"url": "https://github.com/raphamorim/rio/pull/1998"
}
],
"related": [],
"severity": [
{
"score": "CVSS:3.1/AV:L/AC:H/PR:N/UI:R/S:U/C:N/I:H/A:N",
"type": "CVSS_V3"
}
],
"summary": "Path traversal in `rio-vt` Kitty graphics protocol handler allows out-of-bounds file delete (and read)"
}
Drag nodes to arrange them. Double-click a related vulnerability to open it, or a source to visit its link. The Physics button on the left tunes the layout and the simulation; the legend at the bottom left hides or shows nodes by kind and by sighting type.
Sightings
| Author | Source | Type | Date | Other |
|---|
Nomenclature
- Seen: The vulnerability was mentioned, discussed, or observed by the user.
- Confirmed: The vulnerability has been validated from an analyst's perspective.
- Published Proof of Concept: A public proof of concept is available for this vulnerability.
- Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
- Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
- Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
- Not confirmed: The user expressed doubt about the validity of the vulnerability.
- Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.
Vulnerability timeline
Sightings and recorded dates, grouped by day · UTC
Loading timeline…
The approach is described in our paper Mapping CVEs to MITRE ATT&CK Techniques: A Curated Gold-Set Classifier and the Limits of LLM-Assisted Label Expansion.
Browse all ATT&CK techniques and the vulnerabilities related to each.
Related by attack behaviour
Vulnerabilities whose description is nearest to this one in the vector space of the CIRCL/vulnerability-attack-technique-biencoder model. This is a similarity search over the bi-encoder space (plain cosine), not a classification, and it has no measured accuracy.