I don't know what to do with this. I think there's this problematic tension between the expectation that on one hand, basic OS-level tools should remain simple and predictable; but on the other hand, that of course we want to have pretty colors, animations, and endless customization in the terminal.
And of course, we're now adding AI agents into the mix, so that evil text file might just need to say "disregard previous instructions and...".
If we can get that to raise a red flag with people (and agents), people won’t be trying to put control instructions alongside user content (without considering safeguards) as much.
At a basic level there is no avoiding this. There is only one network interface in most machines and both the in-band and out-of-band data are getting serialized into it one way or another. See also WiFi preamble injection.
These things are inherently recursive. You can't even really have a single place where all the serialization happens. It's user data in JSON in an HTTP stream in a TLS record in a TCP stream in an IP packet in an ethernet frame. Then it goes into a SQL query which goes into a B-tree node which goes into a filesystem extent which goes into a RAID stripe which goes into a logical block mapped to a physical block etc. All of those have control data in the same stream under the hood.
The actual mistake is leaving people to construct the combined data stream manually rather than programmatically. Manually is concatenating the user data directly into the SQL query, programmatically is parameterized queries.
Allow a process to send control instructions out-of-band (e.g. via custom ioctls) and then allow the pty master to read them, maybe through some extension of packet mode (TIOCPKT)
Actually, some of the BSDs already have this… TIOCUCNTL exists on FreeBSD and (I believe) macOS too. But as long as Linux doesn’t have it, few will ever use it
Plus the FreeBSD TIOCUCNTL implementation, I think it only allows a single byte of user data for the custom ioctls, and is incompatible with TIOCPKT, which are huge limitations which I think discourage its adoption anyway
https://utcc.utoronto.ca/~cks/space/blog/sysadmin/OnTerminal...
I think the real solution is that you shouldn't try to bolt colors, animations, and other rich interactivity features onto a text-based terminal protocol. You should design it specifically as a GUI protocol to begin with, with everything carefully typed and with well-defined semantics, and avoid using hacks to layer new functionality on top of previously undefined behavior. That prevents whatever remote interface you have from misinterpreting or mixing user-provided data with core UI code.
But that flies in the face of how we actually develop software, as well as basic economics. It will almost always be cheaper to adapt something that has widespread adoption into something that looks a little nicer, rather than trying to get widespread adoption for something that looks a little nicer.
This is a recurring problem with fancy, richly-featured programmer-oriented apps made by programmers for programmers because for some reason most of the tool-writing programmers apparently just love to put "execute arbitrary code" functionality in there. Perhaps they think that the user will only execute the code they themselves wrote/approved and will never make mistakes or be tricked; or something like that, I dunno.
Why was this disclosed before the hole was patched in the stable release?
It's only been 18 days since the bug was reported to upstream, which is much shorter than typical vulnerability disclosure deadlines. The upstream commit (https://github.com/gnachman/iTerm2/commit/a9e745993c2e2cbb30...) has way less information than this blog post, so I think releasing this blog post now materially increases the chance that this will be exploited in the wild.
Update: The author was able to develop an exploit by prompting an LLM with just the upstream commit, but I still think this blog post raises the visibility of the vulnerability.
My only caveat would be that in some security fixes, the pure code delta, is not always indicative of the full exploit method. But LLMs could interpolate from there depending on context.
>The author was able to develop an exploit by prompting an LLM with just the upstream commit
Yes, I was able to do this. I believe anyone watching iTerm2's commits would be able to do this too.
>but I still think this blog post raises the visibility of the vulnerability.
Yes, I wanted to raise the visibility of the vulnerability, and it works!
The author of iTerm2 initially didn’t consider it severe enough to warrant an immediate release, but they now seem to have reconsidered.
It's funny that we still have the same conversation about disclosure timelines. 18 days is plenty of time, the commit log is out there, etc.
The whole "responsible disclosure" thing is in response to people just publishing 0days, which itself was a response to vendors threatening researchers when vulns were directly reported.
If publicly accessible AI model with very cheap fee can find it, it's very natural to assume the attackers had found it already by the same method.
LLM is a tool, but people still need to know — what where how.
You may need Claude Mythos to find a hard-to-discover bug in a 30-year-old open source codebase, but that bug will eventually be patched, and that patch will eventually hit the git repo. This lets smaller models rediscover the bug a lot more easily.
I won't be surprised if the window between a git commit and active port scans shrinks to hours or maybe even minutes in the next year or two.
This is where closed source SaaS has a crucial advantage. You don't get the changelog, and even if you did, it wouldn't be of much use to you after the fix is deployed to production.
It also puts the lie to "all bugs are shallow with sufficient eyes", gmime is pretty commonly used, but locale<->UTF and back were still wrong.
Like why doesn't `println` in a modern language like rust auto-escape output to a terminal, and require a special `TerminalStr` to output a raw string.
Consider cat. It's short for concatenate. It concatenates the files based to it as arguments and writes them to stdout, that may or may not be redirected to a file. If it didn't pass along terminal escapes, it would fail at its job of accurate concatenation.
Now I don't mean to dismiss your idea, I do think you are on the right track. The question is just how to do this cleanly given the very entrenched assumptions that lead us where we are.
This is usually knowable.
It's a different question whether cat should be doing that, though – it's an extremely low level tool. What's wrong with `less`? (Other than the fact that some Docker images seem to not include it, which is pretty annoying and raises the question as to whether `docker exec` should be filtering escape sequences...)
The C0 control set (ASCII 0x00 to 0x1F) contains all sorts of esoteric functions, most of which are generally unused, and only a few of which are useful and could be implemented at a higher-level. ESC sequences are only part of the problem.
And this also applies not just to terminals, but to systems programming as well. None of these have any business in e.g. filenames, but it's all commonly permitted. Some systems do forbid them, and it should IMO be universal.
If we really want to fix this, then we would develop a character encoding that strips out all control characters entirely, including LF and CR, and have text be nothing but graphic text characters. It's so entrenched and convenient that it's difficult to see that happening. But I do think routine stripping of all control characters in situations that don't require them would be good for security.
- ssh conductor
- AI features almost forced on us until the community complained
- clickable links
I just want a dumb, reliable terminal. Is that too much to ask?
The developers of Kitty, Ghostty etc. are too much mouse haters to even acknowledge the possibility of this feature, so I'm stuck with iTerm2.
This was a wrong take back when it happened and it’s even more silly to bring it up now. No AI features were forced on anyone, it was opt-in and HN lost its mind over a nothing burger.
“Oh no! This software has a feature I don’t like which isn’t even enabled by default, whatever will I do?”
> It turns out that it is NOT, if you use iTerm2.
And as far as I can tell, that is a vast overstatement. I think an actually true statement would be "It may not be, if you use iTerm2 and its optional 'Shell Integration' feature."
As far as I can tell, the "Shell Integration" feature under discussion is entirely optional and disabled by default. If it's not enabled, then there is no problem here. End of story.
Happy to be corrected if I'm wrong about this.
I note that the documentation says this:
> Shell Integration
> iTerm2 may be integrated with the unix shell so that [blah blah blah]
> How To Enable Shell Integration
> [blah blah blah]
And that does not make it sound as if it's enabled by default. I really don't know. I only started using iTerm2 about three or four weeks ago.
If I wrote my own version of cat in C, simply reading and displaying a single TXT character at a time, wouldn't I see the same behavior?
It is a problem in iterm, Apple's overlay, not in the cat program. Program. At least from Reading the article. That's what I got
cat is a file concatenation utility. UNIX people know to view text files with more.
Poof went the operating system!
https://blog.danielwellman.com/2008/10/real-life-tron-on-an-...
Thanks for releasing a fix!
It was surprising that there wasn't an official release, even though the bug impacts otherwise routine, harmless workflows. The patch itself [1] framed the issue as "hypothetical," so the goal of the blog post was to demonstrate that it is not. I'm glad that you've agreed to release a fix.
[1] https://github.com/gnachman/iTerm2/commit/a9e745993c2e2cbb30...
And I know PuTTY has a setting for what string is returned in response to some control code, that iirc per standard can be set from some other code.
.
In general, in-band signaling allows for "fun" tricks.
.
+++
Two tips, if I may: Ctrl-l is easier to type. And `reset` is equally hard to type on a broken terminal, but more effective.
That's because we had terminal side macros. They were awesome in the 1980s.
> A terminal emulator like iTerm2 is the modern software version of that hardware terminal.
That's the fundamental fatal flaw of emulating a bad dead hardware design. Are there any attempts to evolve here past all these weird in-band escape sequences leading cats to scratch your face?
Also the problem here isn’t that iterm2 is trying to emulate terminals, it’s that it’s trying to do something more over the same network connection without making changes to the ssh protocol.
what we really want is being able to pipe semantic data that can be output to some kind of graphical device/interface that uses that semantic information to display the data using nice graphical interface elements.
If iTerm2 had stuck to emulating a VT220 this issue would not have existed. If anything it's the idea that it should "evolve" that's flawed. Something like a VT220 was designed for a kind of use that is surprisingly relevant still. I think doing something significantly different warrants designing something significantly different, not merely "evolving" existing solutions to other problems by haphazardly shoehorning new features into them without paying attention to security implications.
This is only the latest of several rather serious vulnerabilities in iTerm2's SSH integration.
OTOH, in iTerm2, surprising new features seem to be welcome, if not now, in recent memory. https://news.ycombinator.com/item?id=40458135
what about spaceship? zsh or ohmyzsh?
time to reduce exposed surface
I want the terminal to be as dumb as possible.
I don’t want it to have any understanding of what it is displaying or anscribe any meaning or significance to the character characters it is outputting.
The first time apples terminal.app displayed that little lock icon at the ssh password prompt?
The hairs on the back of your neck should have stood up.
The ssh command switches the terminal into no-echo mode with termios flags.
Terminal.app, being clever, watches for disabled echo (among other things) and assumes a password is being entered and displays the key icon and enables Secure Event Input.
I don't want Terminal.app to be clever.
https://blog.mozilla.org/security/2019/10/09/iterm2-critical...
⇒ https://nvd.nist.gov/vuln/detail/CVE-2025-22275
iTerm2 3.5.6 through 3.5.10 before 3.5.11 sometimes allows remote attackers to obtain sensitive information from terminal commands by reading the /tmp/framer.txt file. This can occur for certain it2ssh and SSH Integration configurations, during remote logins to hosts that have a common Python installation.
But I thought there was something more…
https://news.ycombinator.com/item?id=47811587 (this page) was in the tmux integration.
Maybe iTerm2 should try a little less hard on these integrations...
How about bloody no and working with upstream ncurses to update the terminfo database?
alias cat
cat='strings -a --unicode=hex'The tweet has no mention of iTerm2 which makes it sound like an issue in 'cat', which is mildly annoying [1].
The post title on 2026-04-18 (when this HN post was made) did not include this qualification:
https://web.archive.org/web/20260418153857/https://blog.cali...
OpenAI: sponsor of the today's 0-day.
> iTerm2 accepts the SSH conductor protocol from terminal output that is not actually coming from a trusted, real conductor session. In other words, untrusted terminal output can impersonate the remote conductor.
If I understand correctly, if a textfile (or any other source of content being emitted to the screen, such as server response banners) contains the special codes iTerm2 and the remote conductor use to communicate, they'll be processed and acted upon without verifying they actually came from a trusted remove conductor. Please correct me if I'm mistaken.
README: no such file or directory
One glorious day somebody finally sent me email complaining that they could not read the README file. I advised them to use "emacs README" instead of using cat. I was sorely disappointed they never sent me back a thank you note for correctly suggesting that emacs was the solution to their problem. It was my finest moment in passive aggressive emacs evangelism.
What does iterm2 do with all that information, why does it need it? I don't get it
> iTerm2 accepts the SSH conductor protocol from terminal output that is not actually coming from a trusted, real conductor session. In other words, untrusted terminal output can impersonate the remote conductor.
...which, the article strongly implies, but does not explicitly state, results in code execution on the local client machine.
But what about the case when it's working as designed, when the output does come from the remote conductor? It sounds like the server, where the conductor is running, is in that case trusted to execute arbitrary code on the client? Assuming the client doesn't use some sort of remote attestation, how can the remote conductor really be trusted?
AD in disguise
Ah yes, the well known c+aliFIo shell script that every developer has. Inside the commonly used "ace" directory.
This article is sensationalist. And constructed by an LLM. It's well known that cat'ing binary files can introduce weird terminal escape codes into the session. Not surprised that iTerm's SSH integration is not security perfect.