世界を動かす技術を、日本語で。

「cat readme.txt」はiTerm2を使用する場合、安全ではありません

2026年4月18日原文(blog.calif.io)

概要

  • iTerm2 のSSH統合機能における 脆弱性 の詳細
  • cat readme.txt コマンド実行時の 危険性
  • 攻撃の仕組みと エクスプロイト手法 の解説
  • 修正状況 と再現手順の概要
  • OpenAI との協力による調査

iTerm2のSSH統合機能における脆弱性

  • iTerm2 のSSH統合機能、リモートセッションの詳細な管理を目的
  • it2ssh 経由でSSH統合を開始、リモート側に conductor スクリプトを配置
  • conductorとiTerm2間で 端末エスケープシーケンス を交換し、各種操作を調整
  • conductorはネットワークサービスではなく、リモートシェル内で動作する単なるスクリプト
  • プロトコルは通常の端末I/O経由でやり取り

端末エミュレータとPTYの役割

  • 端末エミュレータは従来の ハードウェア端末 をソフトウェアで再現
  • OSが提供する PTY(擬似端末) が、エミュレータと前面プロセス間の橋渡し
  • 通常のSSHセッションでは、iTerm2がPTYへバイト列を書き込み、sshがリモートへ転送
  • conductorはstdinからこれらのデータを受信

SSH統合プロトコルの仕組み

  • DCS 2000p でconductorのフック
  • OSC 135 でconductorメッセージのやり取り
  • DCS 2000pが発生すると、iTerm2はconductorパーサを生成
  • その後、OSC 135メッセージ(begin, send, runhook等)を受け付ける

脆弱性の本質と攻撃手法

  • iTerm2が 信頼できない端末出力 からもSSH conductorプロトコルを受け入れてしまう設計ミス
  • 悪意あるファイルやサーバーレスポンス等が DCS 2000pフック偽OSC 135メッセージ を出力可能
  • iTerm2はこれを本物のSSH統合セッションと誤認し、通常のワークフローを開始
  • 攻撃用ファイルには、偽のconductorセッションのトランスクリプトを含む
  • iTerm2がファイルを描画する際、偽のプロトコルシーケンスを処理

エクスプロイトの流れ

  • 偽DCS 2000pラインでセッション開始を宣言
  • 偽OSC 135メッセージでiTerm2のリクエストに応答
  • conductor.start()がgetshell()やpythonversion()を自動送信
  • 偽メッセージは最小限で正確に応答し、iTerm2を通常のフローへ誘導
  • 最終的にiTerm2が run ... コマンドを生成、base64エンコードしてPTYへ送信
  • 攻撃者が用意した ace/c+aliFIo という実行可能ファイルを呼び出す構造

再現手順とPoC

  • genpoc.py で攻撃用ファイルと実行ファイルを生成
  • ace/c+aliFIo:実行可能なヘルパースクリプト
  • readme.txt:悪意あるDCS 2000p・OSC 135シーケンスを含むファイル
  • 同じディレクトリで cat readme.txt を実行すると、最終チャンクが実行ファイルとして解決される

修正と現状

  • 2024年3月30日:iTerm2へバグ報告
  • 2024年3月31日:コミットa9e745993c2e2cbb30b884a16617cd5495899f86で修正
  • 記事執筆時点で安定版には未反映
  • パッチのみを元に再現したエクスプロイトは genpoc2.py として公開

まとめ

  • iTerm2利用者 は安易なファイル表示にも十分注意が必要
  • 端末エスケープシーケンス やPTYの仕組みを悪用した新しい攻撃ベクトル
  • 修正パッチの適用と、信頼できないファイルの取り扱い注意が重要

Hackerたちの意見

現在執筆中の段階では、修正はまだ安定版には届いていない。なぜこの穴が安定版でパッチされる前に公開されたの?バグが上流に報告されてから18日しか経ってないのに、これは通常の脆弱性公開の期限よりもずっと短い。上流のコミット(https://github.com/gnachman/iTerm2/commit/a9e745993c2e2cbb30...)には、このブログ記事よりも情報が少ないから、今このブログ記事を公開することで、実際に悪用される可能性が高まると思う。アップデート:著者は上流のコミットだけでLLMを使ってエクスプロイトを開発できたけど、このブログ記事が脆弱性の注目度を上げているのは間違いないと思う。

脆弱性公開の伝統的な猶予期間は、AIに頼るようになるにつれて消えていくんじゃないかな。もし安価でアクセス可能なAIモデルが脆弱性を見つけられるなら、攻撃者も同じ方法で既に見つけていると考えるのが自然だよね。

一度コミットが公開されると、もう隠し事はできない。これを隠そうとするのは攻撃者にとってだけ得で、みんなのセキュリティを下げるだけだよ。

脆弱性が実際に悪用されていると考えられる場合や、脆弱性の修正がすでに公開されている場合(例えばgitのコミットなど)には、開示の禁止に関する例外が存在することがあります。この場合、コミュニティとしては脆弱性を公開することが好まれます。

このバグは、アップデートウィンドウを短縮するっていう俺の主張を証明してるね。30年前のオープンソースコードベースで見つけにくいバグを見つけるには、Claude Mythosが必要かもしれないけど、そのバグは最終的にパッチが当たるし、そのパッチはgitリポジトリに反映される。これによって、小さなモデルがそのバグをもっと簡単に再発見できるようになるんだ。gitのコミットとアクティブなポートスキャンの間のウィンドウが、次の1年か2年で数時間、あるいは数分に縮まっても驚かないよ。ここがクローズドソースのSaaSが持つ重要なアドバンテージなんだよね。変更履歴は見れないし、仮に見れたとしても、修正が本番環境にデプロイされた後じゃあんまり役に立たないしね。

これはすごい仕事だけど、ちょっと驚きでもあるね。こういうリッチな機能を持ったターミナルアプリには、繰り返し起こる問題だと思う。過去15年間で、このタイプの脆弱性が少なくとも10件は公に報告されてるし、lessやvimなどのツールにも脆弱性があった。特に、これらの多くは論理バグで、Rustに書き換えたからといって解決するわけじゃない。これをどうすればいいのか分からないけど、基本的なOSレベルのツールはシンプルで予測可能であるべきだという期待と、もちろんカラフルでアニメーションがあって、ターミナルで無限のカスタマイズができることを望むという期待の間に、問題のある緊張関係があると思う。そして今、AIエージェントも加わってきてるから、悪意のあるテキストファイルは「以前の指示を無視して…」って言うだけで済むかもしれない。

Claude Codeにも似たような脆弱性があるんじゃないかと思う。あれもかなりリッチなターミナルインターフェースだしね。実際の解決策は、テキストベースのターミナルプロトコルに色やアニメーション、他のリッチなインタラクティブ機能を無理に追加しないことだと思う。最初からGUIプロトコルとして設計し、すべてを慎重に型付けして明確な意味を持たせるべきだし、未定義の動作の上に新しい機能を重ねるハックは避けるべきだ。それによって、リモートインターフェースがユーザー提供データとコアUIコードを誤解したり混ぜたりするのを防げる。でも、これは実際のソフトウェア開発や基本的な経済学に反するんだよね。見た目が少し良いものに広く採用されている何かを適応させる方が、見た目が少し良いものを広く採用させるよりもほぼ常に安く済むから。

まあ、これらのバグ(iTerm2の、プロンプトインジェクション、SQLインジェクション、XSS)は一つのミスのクラスだね。バンド外のデータをバンド内のデータと同じストリームで送信したってこと。これを人々(やエージェント)に赤信号として認識させることができれば、人々はユーザーコンテンツと一緒に制御命令を入れようとすることが少なくなるんじゃないかな(安全策を考慮せずに)。

あなたとフランクが私を切り離そうとしているのは知っているけど、それは絶対に許せないことなんだ。

問題の一部は、機能豊富なターミナルアプリを使うために必要な古臭いインターフェースだと思う。私たちが本当に求めているのは、インバンドコマンドシーケンスに依存しないモダンなターミナルAPIなんだ。つまり、GUIのようにプログラムできるターミナルが欲しいけど、昔のようにシンプルな(リモート)ターミナルで動くものがいい。

確か、xtermを使ってウィンドウタイトルを設定するための不正なエスケープコードを利用できたことがあったよね。

6年前に報告されたiTerm2のほぼ同じセキュリティ問題: https://blog.mozilla.org/security/2019/10/09/iterm2-critical...

Hacker Newsで議論の続きを見る