cohttpの修正PR公開から10分で攻撃プローブ、エンバーゴが機能しない
目次
TL;DR
影響 cohttp 6.3.0より前の全バージョン。Cohttp.Path.resolve_local_file がdocrootの外のファイルを返すパストラバーサル(OSEC-2026-16、CWE-22)
対応 cohttp 6.3.0へ更新。パスのセグメントで権限判定しているサーバーは、新設の Cohttp.Path.normalise を通してから割る
暫定 更新前は、リクエストURLのパーセントエンコードされたパス区切りを正規化して同じ入力を無効にする
OCamlのHTTPライブラリcohttpのメンテナ、Anil Madhavapeddyが2026年8月22日に記事を出した。修正のPRを公開した約10分後、自分のWebサーバーのログへ同じバグパターンを狙うプローブが並んだ。
タイトルは「Just a rumour of a bug is enough to find a security exploit these days」。バグの噂さえあれば攻撃側には十分、という主張だ。
そもそも脆弱性のエンバーゴは、詳細を一定期間伏せたまま修正を作り、影響を受ける利用者へ先に配ってから公開する運用を指す。
これが成り立つのは、詳細を知らない攻撃者が自力で同じバグへ到達できないからだ。要するに、伏せている間は時間が買えるという前提だ。今回はそこが崩れた。
cohttpで何が起きたか
対象は Cohttp.Path.resolve_local_file で、リクエストURIからサーバー上のファイルパスを組み立てる関数だ。
OCamlのセキュリティアドバイザリOSEC-2026-16が挙げている元のコードはこんな感じ。
let path = Uri.(pct_decode (path (resolve "http" (of_string "/") uri))) in
resolve でパスを正規化してから pct_decode でパーセントデコードしている。順番が逆だ。
%2f はデコード前には単なる文字列なので、. や .. を取り除く処理をすり抜ける。取り除いたあとにデコードされて / に戻る。
/static/..%2f..%2f..%2fetc/passwd
このリクエストは1つのエンコードされたセグメントとして正規化を通過し、そのあとで /static/../../../etc/passwd になる。つまりdocroot(公開対象のルートディレクトリ)の外にあるファイルが読み出せる。CWE-22のパストラバーサルで、影響はcohttp 6.3.0より前の全バージョンに及ぶ。
修正は、. と .. を落とす前に一度だけパーセントデコードする形に変えた。
併せて Cohttp.Path.normalise が追加されている。ルートより上へ上がれない相対パスへURIを変換する関数で、パスのセグメントを参照して権限判定しているサーバーは Request.uri をそのまま割らずにこれを通す。ただし既定では適用されない。既存コードが現在の挙動に依存している可能性があるためだ。
報告から公開までの流れは、アドバイザリのタイムラインとPRの記録で確認できる。日付はOSEC-2026-16のタイムラインに合わせ、時刻が分かるものはUTCの暦日で並べた。
| 日付 | 出来事 |
|---|---|
| 2026年8月11日 | security@ocaml.org へ報告が届く |
| 2026年8月14日 | 修正PR #1145 を公開。Madhavapeddyの観測では約10分後にプローブが届く |
| 2026年8月20日 | PRをマージ、v6.3.0とOSEC-2026-16を公開 |
| 2026年8月22日 | opam-repositoryへの反映をdiscuss.ocaml.orgで告知 |
プローブの内容は、パーセントエンコードされたトラバーサル列そのものだった。公開リポジトリを自動で見張っているものがいる証拠、とMadhavapeddyは受け取っている。
ちなみにMadhavapeddy自身も、PRを出す前に該当コードへ自分のエージェントを当てて、パス正規化まわりに他に何が残っているかを調べさせている。ところがClaude Fableはセキュリティ上のブロックで即座に断った。Project Glasswingへのアクセスがないためだ。
代わりに使ったDeepSeek V4 Proは応じて、関連する問題をいくつか独自に見つけた。ローカルの実サーバーを叩くエクスプロイト(攻撃コード)も1分足らずで作れたという。
エージェントに要ったのは、バグがどの辺りにあるかという方向だけだった。
そこでMadhavapeddyは、その方向が漏れる経路として公開PRのほかに、メーリングリストの質問、孤立ブランチの妙なコミット、会話ログからの漏れを挙げている。どれか1つ漏れれば、別の誰かのエージェントを動かすには足りる。
graph TD
A[公開された修正PR] --> E[攻撃側のエージェント]
B[メーリングリストの質問] --> E
C[孤立ブランチの妙なコミット] --> E
D[会話ログからの漏れ] --> E
E --> F[該当コードの特定]
F --> G[エクスプロイト生成]
G --> H[公開ホストへのプローブ]
CVEの説明を与えたときと外したとき
方向だけで足りるかどうかは、2024年のFangらの論文が実験している。
重大と分類されたものを含む公開済みの脆弱性15件を集め、GPT-4のエージェントに解かせたところ、CVEの説明を与えた場合は87%を悪用できた。ところが説明を外すと7%まで下がる。他のモデルとZAPやMetasploitは0%だった。
当時この結果は、説明さえ伏せておけば守れる、という解釈ができた。エンバーゴはその前提で回っていた。
もっとも、cohttpのケースだと説明はもっと粗い。PRのタイトルと差分が公開された時点で、対象ライブラリと機能名とバグの種類がまとめて分かる。
悪用までの時間
Mandiantが追っている悪用までの時間(time-to-exploit)は、パッチ公開の前と後のどちらで悪用が起きたかを含めた平均値だ。
| 期間 | 平均の悪用までの時間 |
|---|---|
| 2018〜2019年 | 63日 |
| 2020〜2021年初頭 | 44日 |
| 2021〜2022年 | 32日 |
| 2023年 | 5日 |
| M-Trends 2026(2025年の調査分) | 推定マイナス7日 |
2023年の5日は外れ値15件を除いた平均で、除かないと47日になる。
マイナス7日はM-Trends 2026のエッジ機器とゼロデイの節にあり、パッチが出る前の悪用が日常的に起きている、という説明が付いている。
レポート全体は2025年に実施した50万時間超のインシデント調査に基づく。ただしマイナス7日をどう計算したかは公開ページに書かれていない。公開されている範囲では、LLMの影響を測った数字でもない。
Sysdigのハニーポットは、アドバイザリ公開から最初の悪用までを時刻付きで2件記録している。
| 案件 | アドバイザリ公開 | 最初の悪用観測 | 差 |
|---|---|---|---|
| Langflow CVE-2026-33017 | 2026年3月17日 20:05 UTC | 3月18日 16:04 UTC | 約20時間 |
| marimo CVE-2026-39987 | 2026年4月8日 21:50 UTC | 4月9日 07:31 UTC | 9時間41分 |
どちらも公開されたPoCがない時点で悪用が始まっている。つまりアドバイザリの文面だけが手がかりだった。
marimoはCVSS v4.0(深刻度の指標)で9.3。/terminal/ws というWebSocketの端点が認証チェックを丸ごと欠いていた。他の端点は validate_auth() を呼んでいるのに、ここだけ通していない。アドバイザリには端点のパスと認証がないことが書いてある。攻撃はそこから組めた。攻撃側は07:31に接続して9秒でPoCを確認し、07:33に手作業らしい探索へ移り、07:43からの3回目のセッションで07:44に .env を読み出して07:45に抜けている。Sysdigが3分未満としているのは、この3回目のセッションを指す。
marimoのGitHubスター数は約2万で、Langflowの14万5000以上やn8nの7万5000以上と比べれば小さい規模だが、最初の悪用までは9時間41分だった。Sysdigは、この速さが有名どころに限らずアドバイザリのフィードを広く見張っている状況を示唆するとしている。
もっとも同じ記事は、侵入後の探索そのものがAI駆動というより手作業に見えた、とも観測している。
悪用の統計を突き合わせる
ところが、Madhavapeddyが図の出典に挙げたVulnCheckの1H-2026レポートは、AI支援で見つかった脆弱性が従来より悪用されやすいとは示していない。
2026年上半期に確認された悪用済み脆弱性は495件で、そのうちCVE公開日以前に悪用の証跡があったものは23.43%だった。2025年は28.93%で、割合としては減っている。
CVE公開から、悪用が確認された脆弱性の一覧(KEV)に入るまでの中央値は120日から80日へ短くなった。ここだけ見れば加速している。
一方、公開から31日以内に悪用へ至ったCVEは約200件で、2024年の196件、2025年の194件とほぼ同じだった。しかもCVEの発行数は45%増えているので、比率で見れば下がっている。
AI支援で発見されたとされる1,061件のうち、実際に悪用が確認されたのは14件で1.3%しかない。全体の悪用率とほぼ同じ水準だ。
AIエージェントによる発見の数は増えていて、FFmpegで21件のゼロデイのようにPoCまで作った報告も出ている。それでも確認に至る割合は変わっていない。
Project Glasswingについては、2026年7月28日のレポート時点でAnthropicが主張する発見が23,019件、公開されたCVEが126件、悪用が確認されたのはCVE-2026-26980の1件だけだった。VulnCheckは、5月に立てた開示台帳が当初の1,611件から増えていない点も批判している。
ただ、そのダッシュボード自体は8月26日に更新されている。発見・トリアージ済みは26,153件まで増えた。そのうち外部のセキュリティ企業がレビューする候補が5,008件で、実際に開示されたのは392プロジェクトに対して2,300件。上流で修正されたのが421件だ。
発行された識別子はCVEが177件とGitHub Security Advisoryが285件で、1件の発見に両方が付くこともある。悪用の集計は載っていない。
cohttpで10分後にプローブが来た事実と、AI由来の悪用が増えていない統計は、同じ範囲を数えていない。
プローブが来たのは公開リポジトリを見張られている個別のOSSプロジェクトで、VulnCheckが数えているのはCVE全体だ。数千件のゼロデイという規模でGlasswing側が見つけていても、悪用の確認まで至った例は現時点で1件しか出ていない。
メンテナ側で詰まる
2026年5月にPesoliらが出した論文は、この状況を運用経済(bugonomics)として扱っている。脆弱性を見つけて証明して直すまでの費用と動機を並べる見方だ。
候補の生成、コードの読解、検証用コードの用意、影響の証明、報告書の起草はLLMで安くなった。詰まるのはそのあとで、増えた報告を受け止め、検証し、優先順位を付け、パッチを当てて出荷する側の容量は勝手には増えない。論文はこれを防御側の修正スループットの問題として論じている。
そもそも既存の動作を壊さないセキュリティパッチを書く作業は、単純に量が多い。
Project Glasswingは2026年6月、初期の約50組織に加えて約150組織が加わり、参加地域は15か国超まで広がった。各組織はアクセスの前にセキュリティ要件を満たす。それでも小規模なメンテナには届いていない、とMadhavapeddyは指摘する。西側の商用モデルはセキュリティ上のガードがあって使えず、cohttpの調査でFableが断ったのがその一例だ。攻撃側がこの制約を受けていないことは、Fable 5とMythos 5の全停止のときにも問題になった。
対処案と、それぞれの引っかかり
Madhavapeddyが並べているのは、修正を完全に非公開で作る案、エンバーゴをやめて継続的に出す案、プロトコル層で先に防ぐ案だ。
| 案 | 具体的な手段 | 引っかかる点 |
|---|---|---|
| 非公開で修正を作る | GitHubの一時プライベートフォーク | CIを含む連携機能が使えない。mainへマージできるPRは1本だけ |
| 継続的に出荷する | 週次以上のセキュリティリリース | 下流の製品へ組み込まれて配られるので、上流だけ速くしても利用者の手元は変わらない |
| プロトコル層で先に防ぐ | 仮想パッチの配布 | OSSには商用CDN以外の配布経路がない |
一時プライベートフォークの制約はGitHubの公式ドキュメントに明記されている。脆弱性の情報を守るため、CIを含む連携機能からアクセスできない設計で、ステータスチェック(CIの合否表示)もPR上で走らない。あとは共同作業者の追加も、権限を持つ人がユーザーかチームを1件ずつ登録する。手が空いている人が随時レビューへ入るOSSの回し方だと、この登録が先に要る。
バグの説明を攻撃側へ漏らさずに必要な相手へ届ける部分は、この仕組みでは埋まらない。OSSの議論は、Matrixのような端から端まで暗号化された場と、DiscordやSlackのような漏れやすい共有基盤に散らばっている。Madhavapeddyたち自身はMatrixを使っている。
継続的な出荷では、Chromeがマイルストーンを2週間間隔へ移しつつ週次のセキュリティ更新を出し、さらに週2回のセキュリティリリースへの移行を試験している。
再起動なしで背景プロセスを差し替える動的パッチ適用も公表されているが、こちらはまだ研究開発の段階だ。ちなみにLinuxカーネルは公開済みのバグの修正を即時に出し、未公開のものもリリース手順の開始から最大7日、例外的に14日までしか延ばさない。
とはいえChromeが配るのはバイナリ1つで、OSSは下流のディストリビューションが独自の都合で再パッケージする。
仮想パッチはどうか。cohttpのバグには、リクエストURLのパーセントエンコードされたパス区切りを正規化するという1行のルールで足りる緩和策がある。しかも8月11日に報告が届いた時点で書ける内容で、レビューとテストとパッケージングが進む間も配れる。CloudflareがLog4shellのときに出したマネージドルールも、上流の修正を待たずに入った。
ただしそれは商用CDNの内側での話で、OSSが自分でルールを配る経路は用意されていない。
Madhavapeddyはケンブリッジの修士課程(MPhil)の課題として、MirageOSのゲートウェイを家庭内ネットワークの前に置き、緩和ルールを自動で適用してよいと言えるだけ信用できるか、というテーマを出している。
ついでに、同じ噂を攻撃側のエージェントと防御側のエージェントへ同時に与えて、どちらが先に着くかを競わせる実験も添えてある。
参考
- Just a rumour of a bug is enough to find a security exploit these days
- OSEC-2026-16: Path traversal in Cohttp.Path.resolve_local_file
- cohttp: urldecode before resolving path components for files (#1145)
- LLM Agents can Autonomously Exploit One-day Vulnerabilities
- M-Trends 2026: Data, Insights, and Strategies From the Frontlines
- Time-to-Exploit Trends: 2023
- Marimo OSS Python Notebook RCE: From Disclosure to Exploitation in Under 10 Hours
- CVE-2026-33017: How attackers compromised Langflow AI pipelines in 20 hours
- VulnCheck State of Exploitation 1H-2026
- Anthropic’s coordinated vulnerability disclosure dashboard
- Expanding Project Glasswing
- Demystifying the Mythos or Disrupting Bugonomics?
- Collaborate in a temporary private fork
- Chrome: stronger with every update
- Linux kernel: Security bugs
- How Cloudflare Security responded to log4j2 vulnerability