Input validation / Bounds checking

HIGH
victoriametrics/victoriametrics
Commit: 93508215d94b
Affected: 1.139.0 and earlier (pre-fix).
2026-07-02 15:00 UTC

Description

The commit adds strict validation for time-series limits to prevent out-of-range values that could lead to data corruption during ingestion. Specifically, maxLabelsPerTimeseries, maxLabelNameLen, and maxLabelValueLen must be within the inclusive range [1, 65535]. The patch introduces a MustInit function that validates these inputs and logs a fatal error if they are out of range, then initializes the limits. This addresses a potential data integrity risk from invalid configuration inputs, by failing fast instead of proceeding with corrupted/unsupported limits.

Proof of Concept

Proof of Concept (reproducible steps): 1) Build VictoriaMetrics with this commit and run vminsert. 2) Start vminsert with an invalid limit, e.g. -maxLabelNameLen=70000 (or -maxLabelNameLen=0). 3) Observe startup failure and exit with a fatal log similar to: incorrect limit: "maxLabelNameLen" value: 70000, must be in range 1..65535 This demonstrates that the process cannot start with out-of-range limits, preventing potential data corruption due to invalid lengths. As an alternative, you can reproduce via a small Go snippet calling MustInit(70000, 100, 100), which will trigger the same fatal path in a test environment.

Commit Details

Author: Nikolay

Date: 2026-07-02 14:41 UTC

Message:

lib/timeserieslimits: properly check range for limit values Limit cannot be 0 or greater then 65535, because it may corrupt ingested data. Historically VictoriaMetrics supported only 65535 bytes len for label name and value. See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/11128

Triage Assessment

Vulnerability Type: Input validation

Confidence: HIGH

Reasoning:

The patch adds validation to ensure limit values (maxLabelsPerTimeseries, maxLabelNameLen, maxLabelValueLen) are within 1..65535, preventing values that could corrupt ingested data. This is an input validation fix with potential security/data integrity implications (e.g., avoiding out-of-range conditions that could be exploited).

Verification Assessment

Vulnerability Type: Input validation / Bounds checking

Confidence: HIGH

Affected Versions: 1.139.0 and earlier (pre-fix).

Code Diff

diff --git a/app/vminsert/main.go b/app/vminsert/main.go index dbb7b748b2b30..e86909f3ac892 100644 --- a/app/vminsert/main.go +++ b/app/vminsert/main.go @@ -68,9 +68,11 @@ var ( "at -opentsdbHTTPListenAddr . See https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt") configAuthKey = flagutil.NewPassword("configAuthKey", "Authorization key for accessing /config page. It must be passed via authKey query arg. It overrides -httpAuth.*") reloadAuthKey = flagutil.NewPassword("reloadAuthKey", "Auth key for /-/reload http endpoint. It must be passed via authKey query arg. It overrides httpAuth.* settings.") - maxLabelsPerTimeseries = flag.Int("maxLabelsPerTimeseries", 40, "The maximum number of labels per time series to be accepted. Series with superfluous labels are ignored. In this case the vm_rows_ignored_total{reason=\"too_many_labels\"} metric at /metrics page is incremented") - maxLabelNameLen = flag.Int("maxLabelNameLen", 256, "The maximum length of label name in the accepted time series. Series with longer label name are ignored. In this case the vm_rows_ignored_total{reason=\"too_long_label_name\"} metric at /metrics page is incremented") - maxLabelValueLen = flag.Int("maxLabelValueLen", 4*1024, "The maximum length of label values in the accepted time series. Series with longer label value are ignored. In this case the vm_rows_ignored_total{reason=\"too_long_label_value\"} metric at /metrics page is incremented") + maxLabelsPerTimeseries = flag.Int("maxLabelsPerTimeseries", 40, "The maximum number of labels per time series to be accepted. Series with superfluous labels are ignored. In this case the vm_rows_ignored_total{reason=\"too_many_labels\"} metric at /metrics page is incremented.") + maxLabelNameLen = flag.Int("maxLabelNameLen", 256, "The maximum length of label name in the accepted time series. Series with longer label name are ignored. In this case the vm_rows_ignored_total{reason=\"too_long_label_name\"} metric at /metrics page is incremented. "+ + "Value must be in range 1..65535.") + maxLabelValueLen = flag.Int("maxLabelValueLen", 4*1024, "The maximum length of label values in the accepted time series. Series with longer label value are ignored. In this case the vm_rows_ignored_total{reason=\"too_long_label_value\"} metric at /metrics page is incremented. "+ + "Value must be in range 1..65535.") ) var ( @@ -106,7 +108,7 @@ func Init() { promscrape.Init(func(_ *auth.Token, wr *prompb.WriteRequest) { prompush.Push(wr) }) - timeserieslimits.Init(*maxLabelsPerTimeseries, *maxLabelNameLen, *maxLabelValueLen) + timeserieslimits.MustInit(*maxLabelsPerTimeseries, *maxLabelNameLen, *maxLabelValueLen) } // Stop stops vminsert. diff --git a/lib/timeserieslimits/timeseries_limits.go b/lib/timeserieslimits/timeseries_limits.go index 921191ae1a541..432adda01ba35 100644 --- a/lib/timeserieslimits/timeseries_limits.go +++ b/lib/timeserieslimits/timeseries_limits.go @@ -30,6 +30,18 @@ var ( maxLabelsPerTimeseries = 40 ) +// MustInit checks if limits are with-in supported range and prepares package for usage +func MustInit(inputMaxLabelsPerTimeseries, inputMaxLabelNameLen, inputMaxLabelValueLen int) { + mustBeInRange := func(name string, limit int) { + if limit <= 0 || limit > math.MaxUint16 { + logger.Fatalf("incorrect limit: %q value: %d, must be in range 1..%d", name, limit, math.MaxUint16) + } + } + mustBeInRange("maxLabelNameLen", inputMaxLabelNameLen) + mustBeInRange("maxLabelValueLen", inputMaxLabelValueLen) + Init(inputMaxLabelsPerTimeseries, inputMaxLabelNameLen, inputMaxLabelValueLen) +} + // Init prepares package for usage func Init(inputMaxLabelsPerTimeseries, inputMaxLabelNameLen, inputMaxLabelValueLen int) { maxLabelsPerTimeseries = inputMaxLabelsPerTimeseries
← Back to Alerts View on GitHub →