CVE-2026-71287
Executive Summary
CVE-2026-71287 is a high-severity time-based blind SQL injection vulnerability affecting Cacti's sanitize_sql_column() function in lib/functions.php. The flawed input sanitization allowlist permits malicious SQL expressions such as SLEEP(5) to pass completely unmodified into unsanitized ORDER BY clauses driven by the sort_column GET parameter across at least four administrative PHP pages. This flaw allows any authenticated Cacti user — regardless of privilege level — to execute arbitrary time-based boolean queries against the backend database, potentially leading to full database compromise, data exfiltration, and in some configurations, remote code execution via stacked queries or file write primitives. The vulnerability carries a CVSS v3.1 score of 8.8 (High) and affects all Cacti deployments where user authentication is enabled and the affected scripts are reachable.
This record — and 170,000+ others — are available via the ValtersIT API. One endpoint replaces five: NVD + GitHub CVE + CISA KEV + EPSS + Nuclei + Exploit-DB, unified.
No signup required
Technical Analysis
The vulnerability resides in the sanitize_sql_column() function defined in lib/functions.php. This function is designed to sanitize user-supplied column names for use in dynamic ORDER BY clauses, which cannot be parameterized using prepared statements in typical MySQL/PHP applications. The sanitization logic employs the following regex:
preg_replace('/[^a-zA-Z0-9_().]/', '', $column)
This allowlist preserves only letters (upper/lowercase), digits, underscores, parentheses, and dots. The inclusion of parentheses and dots is intentional — it enables legitimate expressions like COUNT(id) or table.column. However, this same allowlist also permits arbitrary function calls that contain only these characters. Critically, standard SQL keywords like SLEEP(5), BENCHMARK(10,MD5(1)), and even subquery syntax using parentheses are completely unmodified by the regex.
The sanitized value is then directly concatenated into raw SQL ORDER BY clauses. The vulnerable code pattern appears in at least the following files:
user_log.phputilities.phpuser_domains.phpuser_group_admin.php
The attacker-controlled parameter is the sort_column GET parameter. Because no authentication-level checks are applied to determine whether the requesting user should be allowed to manipulate column ordering, any authenticated Cacti user — including the lowest-privilege "guest" or "viewer" role — can inject arbitrary SQL function calls into the query.
The attack surface is the HTTP GET endpoint of these PHP scripts. Since Cacti is a web-based network monitoring tool, user authentication is mandatory, but by default many Cacti deployments allow registration or have low-privilege default users. The injection point is blind (time-based), meaning the attacker extracts data by observing response delays caused by SLEEP() or conditional time-based constructs like IF(condition, SLEEP(x), 0).
The database backend is typically MySQL or MariaDB. The ORDER BY clause accepts expressions, so ORDER BY IF(1=1,SLEEP(5),0) is valid MySQL syntax. The attacker can chain multiple boolean conditions to exfiltrate data character-by-character from tables such as user_auth (which contains password hashes), settings, polling data, or arbitrary database tables accessible to the Cacti DB user.
Exploitation Scenarios
The following is a concrete step-by-step exploitation chain for CVE-2026-71287:
Reconnaissance and Target Identification:
- The attacker performs internet-wide scanning using Shodan or similar tools with dorks like
http.title:"Cacti"to identify exposed Cacti instances. - They validate the target version by inspecting the login page footer or
/include/global.phpoutput for version strings. - The attacker confirms authentication is required and that basic user registration is either disabled (forcing credential brute-forcing) or enabled (allowing immediate low-privilege account creation).
- The attacker performs internet-wide scanning using Shodan or similar tools with dorks like
Authentication and Initial Access:
- The attacker logs in with either a low-privilege account (e.g., created via self-registration) or a compromised/default credential. Common default credentials like
admin:adminare attempted first. - Once authenticated, the attacker captures their session cookie (e.g.,
CactiSession).
- The attacker logs in with either a low-privilege account (e.g., created via self-registration) or a compromised/default credential. Common default credentials like
Vulnerable Endpoint Identification:
- The attacker requests a page such as
/user_log.phpwith a normalsort_columnparameter to confirm baseline behavior. - They then append a benign-but-verifiable payload like
sort_column=IF(1=1,SLEEP(3),0). If the page responds after a 3-second delay, the endpoint is confirmed vulnerable and the time-based exfiltration channel is validated.
- The attacker requests a page such as
Payload Construction and Data Exfiltration:
- The attacker constructs a time-based blind SQL injection payload using the following pattern:
GET /user_log.php?sort_column=IF(SUBSTRING((SELECT password FROM user_auth WHERE username='admin'),1,1)='a',SLEEP(5),0) - They iterate through character positions and candidate characters, measuring response latency to determine each byte of the target data.
- For efficiency, the attacker may use a binary search approach (e.g., checking
ASCII(SUBSTRING(...)) > 97) to reduce the number of requests from ~95 per character to ~7 per character.
- The attacker constructs a time-based blind SQL injection payload using the following pattern:
Post-Exploitation:
- Once the admin password hash is extracted, the attacker cracks it offline using tools like
hashcat(for MD5 or bcrypt). - After obtaining admin access, the attacker can leverage Cacti's built-in plugin/script execution features (e.g., "Scripts" or "Data Queries") to execute arbitrary OS commands with the privileges of the web server user (typically
www-dataorcacti). - Alternatively, if the database user has
FILEprivileges, the attacker can attempt to write a webshell to the webroot viaSELECT ... INTO OUTFILE.
- Once the admin password hash is extracted, the attacker cracks it offline using tools like
Impact Assessment
The business impact of CVE-2026-71287 is severe. Cacti is a network monitoring platform that often holds sensitive operational data — interface traffic statistics, device credentials (SNMP community strings, API tokens), and infrastructure topology. The vulnerability enables:
- Confidentiality breach (C:H): Full database read access, including Cacti user password hashes, SNMP community strings, device credentials, and potentially stored authentication tokens for external systems.
- Integrity compromise (I:H): The attacker can modify database records to alter monitoring thresholds, delete log entries, plant backdoor accounts, or manipulate poller configuration.
- Availability impact (A:H): Malicious SQL functions can cause denial-of-service via resource exhaustion (
SLEEP(3600)), and unauthorized data deletion can render the monitoring system non-functional. - Blast radius: In many environments, the Cacti database user is configured with elevated privileges (e.g.,
ALL PRIVILEGESon multiple databases), expanding the attack to co-located databases. If Cacti is hosted alongside other web applications on the same server, the attacker may pivot to other services. - Compliance: Organizations subject to PCI DSS, HIPAA, or SOX may face regulatory reporting obligations if monitoring credentials or network data are exfiltrated.
The CVSS subscores confirm this: Attack Vector: Network, Attack Complexity: Low, Privileges Required: Low, User Interaction: None, Scope: Unchanged, with Confidentiality, Integrity, and Availability all rated High.
Detection Guidance
Sigma Rule
title: Cacti sort_column Time-Based SQL Injection Attempt
id: 4f8c9c2a-3b7e-4f1d-9c2b-6a5d8e1f7a3c
status: experimental
description: Detects time-based blind SQL injection attempts targeting the sort_column parameter in Cacti web applications
author: Valters IT Security Team
date: 2026/01/15
logsource:
category: webserver
product: apache
definition: 'Web server access logs for Cacti instances'
detection:
selection:
cs-method: GET
c-uri|contains:
- 'user_log.php?sort_column='
- 'utilities.php?sort_column='
- 'user_domains.php?sort_column='
- 'user_group_admin.php?sort_column='
c-uri|contains|all:
- 'SLEEP'
- 'BENCHMARK'
- 'IF('
- 'SUBSTRING'
- 'ASCII'
condition: selection
falsepositives:
- Legitimate database administration queries (extremely unlikely on a web endpoint)
level: high
tags:
- attack.t1190
- cve.2026-71287
- cwe.89
YARA Rule
rule Cacti_SQLi_orderby_payload
{
meta:
author = "Valters IT Security"
description = "Detects SQL injection payloads targeting Cacti sort_column parameter"
cve = "CVE-2026-71287"
date = "2026-01-15"
severity = "high"
strings:
$sle = "SLEEP(" ascii nocase
$bench = "BENCHMARK(" ascii nocase
$if = "IF(" ascii nocase
$sub = "SUBSTRING(" ascii nocase
$ord = "ORDER BY" ascii nocase
$userlog = "user_log.php" ascii nocase
$util = "utilities.php" ascii nocase
$udom = "user_domains.php" ascii nocase
$ugrp = "user_group_admin.php" ascii nocase
$sortc = "sort_column=" ascii nocase
condition:
(uint16(0) == 0x3c21 or uint16(0) == 0x3c68) and
filesize < 10KB and
($sle or $bench or $if) and
($userlog or $util or $udom or $ugrp) and
$sortc and
($sub or $ord)
}
Suricata IDS Rule
alert http any any -> $HOME_NET any (
msg:"CVE-2026-71287 Cacti sort_column Time-Based SQL Injection";
flow:established,to_server;
http.method; content:"GET"; http.uri;
content:"sort_column="; nocase;
content:"SLEEP"; nocase; distance:0;
pcre:"/sort_column=.*?(SLEEP|BENCHMARK|IF\()/i";
classtype:attempted-admin;
sid: 202671287;
rev:1;
reference:cve,2026-71287;
reference:url,https://nvd.nist.gov/vuln/detail/CVE-2026-71287;
metadata:created_at 2026_01_15, updated_at 2026_01_15;
)
Elastic Detection
sequence by source.ip with maxspan=5m
[network where event.category == "web" and http.request.method == "GET"
and url.path in ("/user_log.php", "/utilities.php", "/user_domains.php", "/user_group_admin.php")
and url.query contains "sort_column="
and url.query matches ".*(SLEEP|BENCHMARK|IF\\(|SUBSTRING|ASCII).*"]
[network where event.category == "web"
and (http.response.bytes > 0 or network.packets > 0)]
This EQL pattern detects two sequential HTTP GET requests from the same source IP hitting vulnerable endpoints with SQL-injection-like payloads that include time-delay functions or conditional extraction primitives.
Splunk SPL Query
index=web sourcetype="access_combined_wcookie"
| where like(uri, "%user_log.php%") OR like(uri, "%utilities.php%")
OR like(uri, "%user_domains.php%") OR like(uri, "%user_group_admin.php%")
| regex uri="(?i)sort_column=.*(sLEEP|BENCHMARK|IF\(|SUBSTRING|ASCII)"
| eval risk_score = case(
match(uri, "(?i)sleep\\(\\s*\\d{3,}\\)"), 90,
match(uri, "(?i)benchmark"), 85,
match(uri, "(?i)substring\\("), 80,
true(), 70)
| stats count by src_ip, uri, risk_score, _time
| sort -risk_score
| table _time, src_ip, uri, count, risk_score
Wazuh OSSEC Rule
<group name="cacti,sql_injection,">
<rule id="100287" level="12">
<if_sid>31122</if_sid>
<match>user_log.php|utilities.php|user_domains.php|user_group_admin.php</match>
<regex>sort_column=.*SLEEP</regex>
<description>Cacti CVE-2026-71287 - Time-based SQLi (SLEEP payload) detected</description>
<group>attack.t1190,sql_injection,cve_2026_71287,</group>
<mitre>
<id>T1190</id>
</mitre>
<options>no_full_log</options>
</rule>
<rule id="100288" level="12">
<if_sid>31122</if_sid>
<match>user_log.php|utilities.php|user_domains.php|user_group_admin.php</match>
<regex>sort_column=.*BENCHMARK</regex>
<description>Cacti CVE-2026-71287 - Time-based SQLi (BENCHMARK payload) detected</description>
<group>attack.t1190,sql_injection,cve_2026_71287,</group>
<mitre>
<id>T1190</id>
</mitre>
<options>no_full_log</options>
</rule>
<rule id="100289" level="10">
<if_sid>31122</if_sid>
<match>user_log.php|utilities.php|user_domains.php|user_group_admin.php</match>
<regex>sort_column=.*IF\(.*SUBSTRING|sort_column=.*IF\(.*ASCII</regex>
<description>Cacti CVE-2026-71287 - Blind SQLi conditional extraction attempt</description>
<group>attack.t1190,sql_injection,cve_2026_71287,</group>
<mitre>
<id>T1190</id>
</mitre>
<options>no_full_log</options>
</rule>
</group>
Mitigation & Patch Guidance
Patch Confidence: 0/4 — UNPATCHED. The vendor has not released an official patch as of this report. The following actions are recommended in order of priority:
Immediate Mitigations (highest priority):
- Restrict access to the affected PHP scripts (
user_log.php,utilities.php,user_domains.php,user_group_admin.php) via web server ACLs. Deny access from untrusted networks and require VPN access for administrative pages. - Disable user self-registration if enabled. Enforce the principle of least privilege by auditing existing accounts and removing guest or viewer roles that are not strictly required.
- Implement a web application firewall (WAF) rule to block requests containing
sort_columnwith suspicious patterns. Example ModSecurity rule:SecRule ARGS:sort_column "@rx (SLEEP|BENCHMARK|IF\(|SUBSTRING|ASCII)" \ "id:100287,phase:2,deny,status:403,msg:'Cacti SQLi blocked'"
- Restrict access to the affected PHP scripts (
Patch/Upgrade Steps:
- Monitor the official Cacti GitHub repository (https://github.com/Cacti/cacti) and the Cacti mailing list (https://lists.cacti.net) for security announcements.
- When a patched version is released (likely 1.2.x+), upgrade immediately. The patch will likely modify
sanitize_sql_column()to use a stricter allowlist or switch to allowlist-based column name mapping rather than expression evaluation. - Until a patch is available, consider applying a manual hotfix: modify the regex in
lib/functions.phpto reject parentheses and dots entirely, or replace the dynamic ORDER BY with a hardcoded whitelist of sortable columns per page.
Long-Term Hardening:
- Apply the principle of least privilege to the MySQL/MariaDB database account used by Cacti. Revoke
FILE,GRANT, andDROPprivileges; grant onlySELECT,INSERT,UPDATE,DELETEon the Cacti database. - Isolate the Cacti database from other applications by using a dedicated database instance or at least a dedicated database user per application.
- Enable MySQL query logging temporarily (or use a database proxy like ProxySQL) to detect anomalous slow queries or
SLEEP()calls. - Implement network segmentation: place Cacti management interfaces behind internal firewalls, accessible only via jump hosts or VPN.
- Regularly audit Cacti user accounts, disabling any that are unused or have not logged in within 90 days.
- Subscribe to the CVE feed and Cacti security advisories. Reassess exposure every time a new patch is released.
- Apply the principle of least privilege to the MySQL/MariaDB database account used by Cacti. Revoke
References
- NVD Entry: https://nvd.nist.gov/vuln/detail/CVE-2026-71287 (NVD JSON feed: https://nvd.nist.gov/vuln/detail/CVE-2026-71287)
- Cacti Official Website & Downloads: https://www.cacti.net/
- Cacti GitHub Repository (source code and issue tracking): https://github.com/Cacti/cacti
- Cacti Mailing List / Security Announcements: https://lists.cacti.net/mailman/listinfo/cacti-announce
- MITRE ATT&CK Technique T1190 (Exploit Public-Facing Application): https://attack.mitre.org/techniques/T1190/
Exploit-in-the-wild status: No public exploit code or active campaign has been reported for this CVE at the time of writing. However, given the low authentication barrier and the ease of crafting time-based blind SQLi payloads, active exploitation is highly likely within 30 days of public disclosure. Security teams should treat this as an actively exploitable vulnerability and implement the mitigations listed above immediately.
What is this? Security researchers use these exact search queries on Shodan.io (a search engine for internet-connected devices) to find vulnerable systems globally. You can copy these dorks to see if your organization's IP space is exposed.
💣 PoC CODE AVAILABLE
Exploit code for this CVE is tracked in our database.
Access poc_code via API Pro.