{"uuid": "3dd9c513-d3c4-4aeb-9b53-7eded711bebb", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2020-27347", "type": "seen", "source": "https://gist.github.com/XlabAITeam/f0d9952595f795129a3258ba73bbc3cb", "content": "### Product\n\nProduct Name: tmux\n\nProduct URL: https://github.com/tmux/tmux.git\n\nAffected Versions: &lt;= tmux 3.6a \n\nFixed Version: tmux 3.6b\n\nFix commit: https://github.com/tmux/tmux/commit/fc6d94a9f8a593bd8b7031650802084385d4ee03\n\n\n\n### Summary\n\ntmux is a widely used terminal multiplexer that allows users to manage multiple sessions within a single terminal window. tmux supports the Sixel graphics protocol (requires the `--enable-sixel` compile flag, which is enabled by default on some platforms such as Homebrew), allowing terminal programs to output pixel images to panes via standard output. Pixel images are centrally managed by the tmux server. Each image structure is simultaneously linked into a global LRU linked list and a per-screen linked list (`s-&gt;images`). The global list enforces a total count limit (default 20); when exceeded, the oldest image is evicted.\n\nWhen a user switches to the alternate screen, tmux migrates all nodes from `s-&gt;images` to `s-&gt;saved_images` in bulk, but the references in the global LRU list remain unchanged. When LRU eviction occurs, the deallocation function `image_free` unconditionally performs a linked-list removal from `s-&gt;images`, without considering that the node may have already been migrated to `s-&gt;saved_images`. Performing a doubly-linked list removal on the wrong list corrupts the list metadata, producing a cross-list out-of-bounds write primitive. Meanwhile, the removed node is immediately freed, but the residual pointer in `s-&gt;saved_images` still points to the freed memory, constituting a use-after-free. \n\nAn attacker can craft a specific byte sequence and trick a user into outputting it within a tmux pane (e.g., by having the user view a maliciously crafted file in a pane). This triggers the memory corruption in the tmux server process running in the user's environment, which can cause the tmux server process to crash, resulting in the loss of all user sessions and windows \u2014 a denial of service. The attacker may further exploit this UAF write primitive for heap layout manipulation to achieve arbitrary code execution.\n\nCWE: CWE-416: Use After Free\n\n\n### Details\n\n`image_free` in `image.c` always removes the target `struct image` from `s-&gt;images`, but after `screen_alternate_on` the image resides in `s-&gt;saved_images` instead. Calling `TAILQ_REMOVE` on the wrong list corrupts the TAILQ doubly-linked list metadata of both `s-&gt;images` and `s-&gt;saved_images`, producing exploitable heap-metadata corruption and/or server crash.\n\n1. Entry Point \u2014 Sixel sequence received from pane process\n\n**File:** `input.c` **Function:** `input_dcs_dispatch()` (line 2583) **Code:**\n\n```c\nsi = sixel_parse(buf, len, p2, w-&gt;xpixel, w-&gt;ypixel);\nif (si != NULL)\n    screen_write_sixelimage(sctx, si, ictx-&gt;cell.cell.bg);\n```\n\n**Issue:** Any data written to a pane's PTY can produce a valid Sixel DCS sequence. This is the untrusted boundary: Spawned Shell / Pane Process \u2192 tmux Server.\n\n2. Image stored and added to both `s-&gt;images` and global `all_images`\n\n**File:** `image.c` **Function:** `image_store()` (lines 139\u2013146) **Code:**\n\n```c\nTAILQ_INSERT_TAIL(&amp;s-&gt;images, im, entry);          // per-screen list\nTAILQ_INSERT_TAIL(&amp;all_images, im, all_entry);     // global LRU list\nif (++all_images_count == MAX_IMAGE_COUNT)\n    image_free(TAILQ_FIRST(&amp;all_images));          // evict oldest\nreturn (im);\n```\n\n**Issue:** The image is linked into both a per-screen list (`s-&gt;images`, via `entry`) and a global list (`all_images`, via `all_entry`). The two linkages are independent fields of `struct image`.\n\n3. Alternate-screen switch silently moves images to `saved_images`\n\n**File:** `screen.c` **Function:** `screen_alternate_on()` (line 667) **Code:**\n\n```c\nTAILQ_CONCAT(&amp;s-&gt;saved_images, &amp;s-&gt;images, entry);\n```\n\n**Issue:** `TAILQ_CONCAT` splices all elements of `s-&gt;images` onto the end of `s-&gt;saved_images` and then sets `s-&gt;images` to empty. After this call every previously-stored image still lives in `all_images` (via `all_entry`) but now lives in `s-&gt;saved_images` (not `s-&gt;images`) via `entry`. The `im-&gt;s` backpointer still points to the same `screen *s`.\n\n4. Eviction via LRU calls `image_free` with wrong per-screen list\n\n**File:** `image.c` **Function:** `image_free()` (lines 54\u201367) **Code:**\n\n```c\nstatic void\nimage_free(struct image *im)\n{\n    struct screen *s = im-&gt;s;\n\n    TAILQ_REMOVE(&amp;all_images, im, all_entry);    // correct: removes from global list\n    all_images_count--;\n\n    TAILQ_REMOVE(&amp;s-&gt;images, im, entry);         // BUG: im is in s-&gt;saved_images, not s-&gt;images\n    sixel_free(im-&gt;data);\n    free(im-&gt;fallback);\n    free(im);\n}\n```\n\n**Issue:** `image_free` unconditionally removes `im` from `s-&gt;images`. If the image has been moved to `s-&gt;saved_images` by `screen_alternate_on`, this is the wrong list. `TAILQ_REMOVE` on the wrong TAILQ corrupts both list's head/tail/prev pointers. See Vulnerability Description for the exact corruption.\n\n5. Corruption propagated on next list operation\n\n**File:** `image.c` (and callers) **Function:** any subsequent TAILQ operation on `s-&gt;images` or `s-&gt;saved_images` **Code:**\n\n```c\n// Any of: TAILQ_INSERT_TAIL(&amp;s-&gt;images, ...), TAILQ_FOREACH_SAFE(..., &amp;s-&gt;images, ...),\n//          TAILQ_CONCAT(&amp;s-&gt;images, &amp;s-&gt;saved_images, entry)   [in screen_alternate_off]\n```\n\n**Issue:** A corrupted TAILQ causes write-what-where heap corruption, use-after-free when iterating, or NULL dereference, depending on what state the list was left in by the `TAILQ_REMOVE` of a non-member.\n\n\n\n### Impact\n\nAn attacker can craft a specific byte sequence and trick a user into outputting it within a tmux pane (e.g., by having the user view a maliciously crafted file in a pane). This triggers the memory corruption in the tmux server process running in the user's environment, which can cause the tmux server process to crash, resulting in the loss of all user sessions and windows \u2014 a denial of service. The attacker may further exploit this UAF write primitive for heap layout manipulation to achieve arbitrary code execution.\n\n\n\n### Score\n\nSeverity: High, CVSS 4.0 Score: 7.8, Details: AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H\n\n(Score referenced from CVE-2020-27347)\n\n\n\n### Credit\n\nThis vulnerability was discovered by:\n\n- XlabAI Team of Tencent Xuanwu Lab (xlabai@tencent.com)\n- Atuin Automated Vulnerability Discovery Engine\n- Guannan Wang (wgnbuaa@gmail.com), Zhanpeng Liu (pkugenuine@gmail.com), Guancheng Li (lgcpku@gmail.com)\n\n", "creation_timestamp": "2026-05-22T06:27:44.000000Z"}