Skip to main content
CVE Vulnerability Database
Vulnerability Database/CVE-2026-39894

CVE-2026-39894: Cacti Information Disclosure Vulnerability

CVE-2026-39894 is an information disclosure vulnerability in Cacti that causes locale-dependent decimal formatting to corrupt RRDtool metric values. This article covers the technical details, affected versions, and mitigation.

Published:

CVE-2026-39894 Overview

Cacti is an open source performance and fault management framework used to collect and graph time-series data through RRDtool. CVE-2026-39894 affects Cacti versions 1.2.30 and below. The rrdtool_function_update() function relies on PHP string interpolation to build RRDtool update commands. When the server LC_NUMERIC locale uses a comma as the decimal separator, float values like 1.5 are serialized as "1,5". RRDtool expects a period, so metric values shift into the wrong columns or are silently dropped. The flaw causes a data integrity issue in collected metrics. It is not remotely exploitable and requires a misconfigured server locale [CWE-474].

Critical Impact

Silent corruption or loss of monitoring metric data when the host server runs under a non-C/en_USLC_NUMERIC locale, undermining capacity planning, alerting, and forensic time-series analysis.

Affected Products

  • Cacti 1.2.30 and earlier 1.2.x releases
  • Cacti deployments with server LC_NUMERIC set to a locale using comma as decimal separator (for example, de_DE, fr_FR, it_IT)
  • Any RRDtool data sources updated through the affected rrdtool_function_update() code path

Discovery Timeline

  • 2026-06-24 - CVE-2026-39894 published to the National Vulnerability Database (NVD)
  • 2026-06-25 - NVD record last modified
  • Version 1.2.31 - Cacti releases the fixed version via commit d2a698854956e9e4e53da9eab5b5719ae40e6893

Technical Details for CVE-2026-39894

Vulnerability Analysis

The vulnerability lives in lib/rrd.php inside the rrdtool_function_update() function. Cacti validates each polled value with is_numeric() and then concatenates the value directly into the RRDtool update command using PHP string interpolation. PHP's implicit float-to-string cast honors the active LC_NUMERIC locale. On a host configured with a European locale, a float 1.5 becomes the string "1,5". RRDtool parses update payloads as colon-separated tuples with . as the decimal point. A comma in the value confuses the field parser, causing values to land in the wrong data source slot or be discarded entirely. No setlocale() reset guards the update path, so the corruption persists across every poll cycle.

Root Cause

The root cause is unsafe trust of locale-dependent type coercion at an inter-process communication (IPC) boundary [CWE-474, control of filename or path for include/require statement and improper resource resolution category]. The code treats is_numeric() as sufficient sanitization, but is_numeric() accepts the PHP float while ignoring how that float will later be serialized. There is no canonicalization step to force the C locale numeric format before handing data to RRDtool.

Attack Vector

This is a local, low-impact data integrity issue rather than a remote exploitation path. It requires the Cacti server itself to run under a locale where LC_NUMERIC defines comma as the decimal separator. An administrator setting LANG=de_DE.UTF-8 or similar at the system or web server level is enough to trigger silent metric corruption. There is no authentication, network access, or user interaction required from an attacker, but there is also no privilege gain or confidentiality impact, only degraded integrity of stored RRD files.

php
// Source: https://github.com/Cacti/cacti/commit/d2a698854956e9e4e53da9eab5b5719ae40e6893
// Security patch in lib/rrd.php enforcing strict metric serialization at the RRDtool IPC boundary

					$rrd_update_template .= $field_name;

-					/* if we have "invalid data", give rrdtool an Unknown (U) */
-					if (!isset($value) || !is_numeric($value)) {
-						$value = 'U';
+					/* Sanitize control characters that poison the rrdtool IPC pipe */
+					if (is_string($value)) {
+						$value = trim($value);
					}

-					$rrd_update_values .= $value;
+					/* Enforce strict fail-closed NaN propagation */
+					if ($value === null || $value === '' || !is_numeric($value)) {
+						$rrd_update_values .= 'U';
+					} else {
+						/* Force standard decimal separator to bypass LC_NUMERIC locale
+						   bugs without truncating 64-bit counter precision */
+						$rrd_update_values .= str_replace(',', '.', (string)$value);
+					}
				}

The patch trims string values, fails closed to RRDtool's U (Unknown) sentinel for non-numeric input, and forces the decimal separator back to . regardless of LC_NUMERIC.

Detection Methods for CVE-2026-39894

Indicators of Compromise

  • RRDtool update commands in Cacti debug logs containing comma decimal separators, for example update ... N:1,5:2,3.
  • RRD files showing unexpected NaN/U gaps or values shifted between data sources following a recent locale change on the Cacti server.
  • System environment showing LC_NUMERIC or LANG set to a locale such as de_DE, fr_FR, or pt_BR on a Cacti poller host running version 1.2.30 or earlier.

Detection Strategies

  • Inspect Cacti's RRDtool debug output by enabling poller debug logging and grepping for , inside the value portion of update commands.
  • Audit installed Cacti versions across the estate and flag any host running 1.2.30 or below for review.
  • Run locale on Cacti poller hosts and compare against the documented baseline locale (C, C.UTF-8, or en_US.UTF-8).

Monitoring Recommendations

  • Alert on sudden increases in NaN or unknown samples across RRD data sources after deployment or configuration changes.
  • Track configuration drift on /etc/locale.conf, /etc/default/locale, and web server environment files on Cacti hosts.
  • Correlate Cacti version inventory with locale telemetry from endpoint or configuration management tooling to surface vulnerable combinations.

How to Mitigate CVE-2026-39894

Immediate Actions Required

  • Upgrade Cacti to version 1.2.31, which includes commit d2a698854956e9e4e53da9eab5b5719ae40e6893.
  • Set LC_NUMERIC=C for the user and web server process running Cacti pollers until the upgrade is applied.
  • Review historical RRD data for the period during which a comma-decimal locale was active and flag affected dashboards as untrusted.

Patch Information

The fix is published in Cacti 1.2.31. The patch in lib/rrd.php enforces strict metric serialization at the RRDtool IPC boundary, trims string values, sends U for non-numeric input, and replaces any comma in the serialized value with a period before writing to the update pipe. See the Cacti GitHub Security Advisory GHSA-23g4-vf2j-94w4, the upstream commit, and the GitHub issue discussion for details.

Workarounds

  • Force the Cacti poller and web server to run under the C or en_US.UTF-8 locale by exporting LC_NUMERIC=C in the service unit or web server environment.
  • Add setlocale(LC_NUMERIC, 'C'); early in the Cacti bootstrap as a stopgap if upgrading immediately is not possible.
  • Avoid setting system-wide locales that use comma as the decimal separator on hosts that run Cacti pollers.
bash
# Configuration example: pin LC_NUMERIC to C for the Cacti service and cron poller

# /etc/systemd/system/cacti-poller.service.d/override.conf
[Service]
Environment="LC_NUMERIC=C"
Environment="LANG=C.UTF-8"

# /etc/cron.d/cacti
LC_NUMERIC=C
LANG=C.UTF-8
*/5 * * * * www-data php /var/www/html/cacti/poller.php >/dev/null 2>&1

# Verify the active locale for the Cacti runtime user
sudo -u www-data locale | grep LC_NUMERIC

Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

Default Legacy - Prefooter | Experience the World’s Most Advanced Cybersecurity Platform

Experience the Most Advanced Cybersecurity Platform

See how the world’s most intelligent, autonomous cybersecurity platform can protect your organization today and into the future.