iTerm2 CVE-2026-41253: SSH Conductor Protocol Confusion Lets `cat readme.txt` Run Arbitrary Code
Contents
CVE-2026-41253, disclosed on 2026-04-18, targets the SSH Integration feature in iTerm2 3.6.9 and earlier.
Opening a crafted text file with cat is enough to run an executable sitting in the same directory.
The attack vector itself — terminal escape sequence injection — is a class that has existed for a quarter century, but the target this time is impersonation of iTerm2’s conductor (the control agent iTerm2 installs on the remote SSH host), which is new.
The discoverers are Calif Global, working with OpenAI under the MAD Bugs program (Month of AI-Discovered Bugs, a monthly showcase of vulnerabilities surfaced by AI). They reported it to the iTerm2 developer on 2026-03-30, and commit a9e7459 landed a fix the next day.
However, the fix had not yet shipped in a stable build at the time of disclosure, and Hacker News saw plenty of criticism that “going public before a fix is out is premature.”
The vulnerable surface includes README files fetched with curl, repositories cloned with git clone, text on NFS/SMB mounts, and long blocks pasted from Slack — basically any path where “untrusted bytes you brought onto your machine get written to the terminal.”
It belongs to the same current as Anthropic digging up a 23-year-old Linux kernel NFS bug and Claude Mythos Preview finding thousands of zero-days in Project Glasswing: AI finds the bug, humans take the handoff.
What’s Actually Going On
iTerm2 grafts SSH Integration onto a plain terminal.
A normal terminal just passes the contents of the SSH session through transparently. It has no idea which command is running, what the remote working directory is, or how to move files around.
iTerm2 wraps the ssh command, bootstraps a small helper (the conductor) on the remote side at connection time, and runs its own protocol between local and remote.
The transport for that protocol is the PTY itself, with control messages carried on DCS (Device Control String) and OSC (Operating System Command) escape sequences.
| Sequence | Full Name | Standard Use | iTerm2 Extension |
|---|---|---|---|
DCS (ESC P) | Device Control String | Terminal device control strings | Conductor handshake DCS 2000p |
OSC (ESC ]) | Operating System Command | Window title, etc. | Conductor responses under OSC 135 |
OSC 133 | — | Shell integration (originated in FinalTerm) | Prompt position notification |
OSC 7 | — | Current directory notification | Shares cwd as a file:// URI |
The problem is that “the channel where the protocol runs” and “the channel where regular text output flows” coexist completely on the same PTY.
From iTerm2’s view, a sequence starting with DCS 2000p is “a conductor session declaration,” and OSC 135 is “a conductor response.”
There was no mechanism to tell whether the sender was a real conductor process or just the contents of a file coming through cat.
The NVD description puts it plainly: “iTerm2 accepts SSH conductor protocol messages even via terminal output that did not originate from a legitimate conductor session.”
In CWE terms this is a combination of CWE-345 (Insufficient Verification of Data Authenticity) and CWE-74 (Neutralization), a textbook case of in-band signaling where the control channel and the data channel share the same byte stream.
Lineage of Terminal Escape Injection
This class of bug is not new.
The history of terminals mixing “bytes for display” and “bytes for control” without separating them is itself the soil for these vulnerabilities, and they resurface periodically.
| Year | Target | Description |
|---|---|---|
| 2003 | xterm / rxvt | The window title could be written via OSC 0 and read back via CSI 21 t, so a cat of a malicious file could inject arbitrary commands back into the shell |
| 2008 | GNOME Terminal / Konsole | Same family of bug resurfaced; patches disabled the readback |
| 2017 | Alacritty / Mintty | A spate of OSC 52 base64 clipboard issues where just viewing a file could write arbitrary content to the clipboard |
| 2025 | tmux / ghostty | External files toggling DEC Private Modes, injection across Bracketed Paste boundaries |
| 2026 | iTerm2 | The SSH conductor protocol confusion described here |
Two countermeasures have historically carried the load.
One is disabling readback mechanisms like Device Status Report, and the other is Bracketed Paste Mode (DEC mode 2004), which distinguishes pastes from typed input.
This iTerm2 bug cuts a new attack surface that neither of those addresses.
Overview of the Conductor Protocol
Inside SSH Integration, local iTerm2 and the remote conductor exchange messages through a state machine like this.
flowchart LR
A[iTerm2 local] -->|DCS 2000p hook| B[Conductor session starts]
B -->|Sends base64 command| C[Conductor runs the command]
C -->|OSC 135 begin id| D[Output start notification]
D -->|stdout lines| E[Output forwarding]
E -->|OSC 135 end id status r| F[Output end notification]
F -->|unhook| A
Commands sent to the conductor are base64-encoded and carried as the inner payload of DCS 2000p.
The conductor decodes the base64, executes it, streams the result between OSC 135 begin <id> and OSC 135 end <id> <status> r, and finally closes the session with unhook.
Remote working-directory tracking, file fetching, and environment variable sync are all implemented as microprotocols on top of this pipe.
In short, iTerm2 was wired as “treat these specific escape sequences specially,” so anything running in the local shell that can emit the same byte patterns gets interpreted as a conductor message by iTerm2.
There wasn’t even a check for whether the output was coming through the ssh process.
Attack Chain
The real exploitation path looks like this.
flowchart TD
U[User cds into a shady directory] --> H[Directory contains readme.txt and ace/c+aliFIo]
H --> C[Runs cat readme.txt]
C --> P[readme.txt contents reach the PTY]
P --> F[Forged DCS 2000p declares a conductor session]
F --> S[Forged OSC 135 answers iTerm2's shell probe]
S --> V[pythonversion check is made to fail on purpose]
V --> R[iTerm2 issues a run command]
R --> E[base64 resolves to ace/c+aliFIo and runs]
E --> X[Attacker code executes]
The trigger readme.txt is packed with a forged DCS 2000p that pretends to be a conductor session and a sequence of OSC 135 messages that impersonate responses to iTerm2’s probes.
The attacker has full control of the sshargs field, which determines what ends up inside the base64 payload iTerm2 constructs later.
iTerm2 takes the conductor’s “responses” at face value and issues a run command.
The resolved path is rigged to point at ace/c+aliFIo under the current working directory.
The file just needs the executable bit set — it can be a shell script or a binary, either way it runs directly.
The odd ace/c+ prefix is chosen because it is valid in the base64 alphabet used along the conductor encoding path and also a valid POSIX relative path — a deliberate two-faced form.
In Calif’s own words, it is a “hypothetical in-band signaling abuse,” a structural issue that follows you as long as the control and data channels share the same pipe.
PoC Layout
The published genpoc.py creates these two files.
| File | Role |
|---|---|
ace/c+aliFIo | The helper script, with the executable bit. This is what ultimately runs |
readme.txt | Plain text containing the forged DCS 2000p and OSC 135 sequences |
The only condition is “run cat readme.txt in a directory that contains ace/c+aliFIo.”
There is no SSH session involved — the whole thing closes inside a local working directory.
Pipelines like curl example.com/malicious.txt | cat trigger it too, as long as the output hits iTerm2’s PTY.
The trigger isn’t limited to cat. less -R, more, head, tail, strings, od -c — any tool that dumps raw bytes to the terminal without suppressing escape sequences qualifies.
git log and git diff work too if the payload is hiding in a commit message or patch content.
The same goes for log viewers like docker logs or journalctl -xeu: any tool that forwards bytes stored in a log straight to the PTY is in scope.
Immediate Mitigations
- Upgrade iTerm2 to 3.7.0 or later (which includes the fix commit
a9e7459). - On unpatched systems, avoid using commands that emit raw bytes to the terminal (
cat,less -R,head, etc.) inside untrusted directories. Be especially wary of working directories that happen to contain an unfamiliarace/c+directory or strangely named files. - Avoid
less -r(raw passthrough) and standardize on the default-R(filtered) behavior.cat -vto make control characters visible as^Xis also a useful habit. - Users who do not rely on SSH Integration can temporarily disable it to shrink their attack surface. Turn off
Settings > Advanced > "Enable SSH Integration"in iTerm2. - Go back to the old-school practice of inspecting externally sourced logs and text with
hexdump -Corxxdfirst. That still works as a first-line defense against VT sequence issues generally.
Since almost any path that dumps text to a PTY qualifies, pasting content copied from a browser is also dangerous unless Bracketed Paste Mode (DEC mode 2004) is enabled.
The clipboard access settings under iTerm2 > Settings > General > Selection are worth a second look too.
CVSS and Severity
The CVSS base score is 6.9 (Medium).
It looks modest for an RCE, because the prerequisite “the attacker must be able to place an executable in the working directory” is baked in.
Even so, the scenario of smuggling it into a Git repository as part of ransomware or a targeted attack is realistic enough to matter.
Much like the recent npm Strapi plugin malware implant and Apache ActiveMQ’s Jolokia RCE entering KEV, slipping into places developers touch every day is just more efficient from an attacker’s point of view.
The “missing transport trust” angle isn’t iTerm2-specific either. RCE via filenames read during tab completion and command injection through terminal title write sequences have been reported over and over.
What makes this case a little different is that the boundary itself sits on a PTY — a channel that can’t be physically separated — which makes the problem genuinely hard at the design level.
Criticism of the Disclosure Process
Publication was on 2026-04-18, at the same moment CVE-2026-41253 was registered on NVD.
The fix commit was already in the public tree, but no stable build had shipped yet.
That left a window of “public but no mitigation on users’ machines,” and multiple voices on Hacker News called it “effectively a zero-day.”
Calif appears to deliberately choose this short-disclosure style. The MAD Bugs program itself doubles as a showcase for “how many and how fast AI can find bugs.”
The OpenAI collaboration hints that Codex sped up the research loop, with code reading and fuzzing partly offloaded to an LLM. That combination is compressing the distance from discovery to PoC at a pace never seen before.
This connects to OpenAI’s Codex Security choosing not to emit SAST-style reports: AI-driven code scanning in the field is already entering a phase where “the human review cycle can’t keep up.”
The flip side is a drift away from end-user update paths, and that shift is impossible to miss.
Like the macOS 49.7-day TCP bug, cases where a vulnerability goes public ahead of any platform-side patch keep happening.
Takeaways for Terminal Developers
The lesson for protocol designers of terminal apps is clear.
If you are going to put control signals on the same pipe as screen output, you must authenticate the sender.
Concretely, that means one or a combination of:
- Issue a random challenge at transport start and require the conductor to respond with a token only it knows
- Attach an HMAC or signature to conductor messages, with a key handed off out-of-band that only local iTerm2 knows
- Like OSC 133 and other industry-standard shell integration sequences, separate “trusted sequences” from “displayable text” with a dedicated side channel from the start
- Use a side channel instead of the PTY — an extra FD, a Unix domain socket, or a named pipe — for control messages
Which approach iTerm2’s 3.7.0 patch took is best seen in commit a9e7459.
The behavior suggests a source-check was added: the conductor session establishment is now limited to output coming through the ssh process iTerm2 itself launched. At a minimum, arbitrary PTY output can no longer bring up the conductor protocol.
As terminal multiplexers (tmux, screen, zellij), Kitty Graphics Protocol, Sixel, shell integration (OSC 133 / OSC 7), and custom extensions like SSH Integration pile on, the PTY becomes a more tangled and dangerous place where control and display channels overlap.
The old practice of viewing output from untrusted sources through raw-byte-safe tools like less -S or hexdump -C still pulls surprising weight.
- Source: MAD Bugs: Even “cat readme.txt” is not safe if you use iTerm2 - Calif
- CVE: CVE-2026-41253 - GitHub Advisory GHSA-5pgv-4jf4-9r43
- Fix commit:
a9e745993c2e2cbb30b884a16617cd5495899f86(2026-03-31) - Fixed version: iTerm2 3.7.0 or later