Potential Ghost CMS Content API SQL Injection Attempt - BROAD
SIGMA detection rule by Adama ASSIONGBON (SOC & CTI Consultant), https://linkedin.com/in/adama-assiongbon-9029893a · Unknown
Detects SQL injection attempts against the Ghost CMS Content API via the filter parameter. Covers boolean-based blind SQLi patterns including CASE WHEN, IF(), CHAR_LENGTH, EXP(), GTID_SUBSET and EXTRACTVALUE, all illegitimate in Ghost NQL filter syntax. BROAD. SOC L1 should verify the source, affected host, user, process or request fields, timing, and related activity.
Détecte les tentatives d'injection SQL contre l'API Content de Ghost CMS via le paramètre filter. Couvre les patterns SQLi boolean-based blind incluant CASE WHEN, IF(), CHAR_LENGTH, EXP(), GTID_SUBSET et EXTRACTVALUE, tous illégitimes dans la syntaxe NQL du filtre Ghost. Toute présence de ces fonctions SQL dans le paramètre filter de l'API Content est suspecte. Règle BROAD : couvre les variants d'évasion (AM2) et les outils de scan automatisés. Le SOC L1 doit vérifier la source, l’hôte affecté, l’utilisateur, les champs de processus ou de requête, la chronologie et les activités associées.
title: Potential Ghost CMS Content API SQL Injection Attempt - BROAD
id: 7c3a8f2e-9b1d-4e5a-b7c0-3f6d2a8e1b94
status: experimental
description: |
Detects SQL injection attempts against the Ghost CMS Content API via the filter parameter. Covers boolean-based blind SQLi patterns including CASE WHEN, IF(), CHAR_LENGTH, EXP(), GTID_SUBSET and EXTRACTVALUE, all illegitimate in Ghost NQL filter syntax. BROAD. SOC L1 should verify the source, affected host, user, process or request fields, timing, and related activity.
Détecte les tentatives d'injection SQL contre l'API Content de Ghost CMS via le paramètre filter. Couvre les patterns SQLi boolean-based blind incluant CASE WHEN, IF(), CHAR_LENGTH, EXP(), GTID_SUBSET et EXTRACTVALUE, tous illégitimes dans la syntaxe NQL du filtre Ghost. Toute présence de ces fonctions SQL dans le paramètre filter de l'API Content est suspecte. Règle BROAD : couvre les variants d'évasion (AM2) et les outils de scan automatisés. Le SOC L1 doit vérifier la source, l’hôte affecté, l’utilisateur, les champs de processus ou de requête, la chronologie et les activités associées.
related:
- id: b4f9e1c7-2d3a-4f8b-9e0c-5a7b3d1e6f20
type: derived
references:
- https://www.cve.org/CVERecord?id=CVE-2026-26980
- https://github.com/advisories/GHSA-w52v-v783-gw97
- https://github.com/gagaltotal/CVE-2026-26980-Ghost-CMS-Api
- https://ghost.org/changelog/6-19-1/
author: Adama ASSIONGBON (SOC & CTI Consultant), https://linkedin.com/in/adama-assiongbon-9029893a
date: 2026-06-27
tags:
- attack.initial-access
- attack.t1190
- attack.credential-access
- attack.t1552
- attack.t1552.001
- cve.2026-26980
logsource:
category: webserver
definition: >
Web server or reverse proxy access logs with UriPath (or Uri/Url), QueryString, SrcIp,
HttpMethod and StatusCode fields. Ensure the SIEM pipeline URL-decodes QueryString before
matching, encoded payloads (e.g. EXP%28710%29) will not match otherwise. Compatible with
nginx, Apache, Caddy, HAProxy, Cloudflare, AWS WAF and similar sources.
detection:
selection_endpoint:
UriPath|startswith: '/ghost/api/content/'
selection_filter_param:
QueryString|contains:
- 'filter='
- 'filter%3D'
# AM-NEW-2 fix: RFC 3986 allows lowercase hex digits (%3d = %3D = '=')
- 'filter%3d'
# All patterns below are illegitimate in Ghost NQL filter syntax.
# A legitimate filter uses NQL expressions like: filter=tag:hash-welcome
# Any SQL function keyword in the filter parameter indicates injection.
selection_sqli_keywords:
QueryString|contains:
- 'CASE WHEN'
- 'CASE%20WHEN'
# AM-NEW-1 fix: MySQL is case-insensitive for SQL keywords
- 'case when'
- 'case%20when'
- 'CHAR_LENGTH'
- 'char_length'
- 'SUBSTR('
- 'substr('
- 'SUBSTRING('
- 'substring('
- 'ASCII('
- 'ascii('
- 'MID('
- 'mid('
- 'EXP('
- 'EXP%28'
- 'exp('
- 'exp%28'
- 'ORD(SUBSTR'
- 'ord(substr'
- 'GTID_SUBSET'
- 'gtid_subset'
- 'EXTRACTVALUE'
- 'extractvalue'
- 'UPDATEXML'
- 'updatexml'
- 'JSON_KEYS'
- 'json_keys'
- 'information_schema'
- 'SLEEP('
- 'sleep('
- 'BENCHMARK('
- 'benchmark('
# AM2 fix: IF()-based boolean injection (alternative to CASE WHEN)
- 'IF(1='
- 'IF%281%3D'
- 'if(1='
- 'if%281%3D'
- 'IF(0='
- 'IF%280%3D'
- 'if(0='
- 'if%280%3D'
- 'IF(CHAR'
- 'if(char'
- 'IF(ORD'
- 'if(ord'
# Optional: suppress authorised scanner noise. Use /32 IPs only.
filter_optional_known_scanners:
SrcIp|startswith:
- '192.0.2.' # placeholder, replace with your scanner IPs
condition: selection_endpoint and selection_filter_param and selection_sqli_keywords and not filter_optional_known_scanners
fields:
- SrcIp
- HttpMethod
- UriPath
- QueryString
- StatusCode
- UserAgent
falsepositives:
- Authorized penetration testing or vulnerability scanning, add scanner IPs to filter_optional_known_scanners
- WAF testing tools sending generic SQL injection payloads
- Security researchers validating patch status on their own instances
level: medium