firefox, go-ethereum, imagemagick, influxdb, micronaut-core, openbsd, proton, proxysql, sqlite, vim. All CWE-407.
4.3 KiB
InfluxDB — CWE-407 Disclosure Brief
2026-04-14 · Patch available — awaiting upstream merge
Finding
Two O(n²) defects in InfluxDB 3.x (influxdb3): one in the persisted files deduplication logic and one in the table definition series key membership check. Both patched. Patches ready for upstream review. The persisted files defect fires on every snapshot load and file persistence event; the series key defect fires on every add_columns call during schema evolution.
The Defects
influxdb-0001 (PATCHED — HIGH): influxdb3_write/src/write_buffer/persisted_files.rs
// update_persisted_files_with_snapshot — Vec::contains per file:
let mut filtered_files: Vec<ParquetFile> = new_parquet_files
.iter()
.filter(|file| !table_files.contains(file)) // O(T) per file
.cloned()
.collect();
// add_persisted_file — Vec::contains per insert:
if !existing_parquet_files.contains(parquet_file) { // O(N) linear scan
existing_parquet_files.push(parquet_file.clone());
}
Two call sites use Vec::contains() for deduplication. In update_persisted_files_with_snapshot, each new parquet file checks against all existing table files: O(F x T) where F = new files, T = existing files. In add_persisted_file, each insert scans the full vec: O(N) per call. Both scale quadratically as tables accumulate parquet files.
influxdb-0002 (PATCHED — MEDIUM): influxdb3_catalog/src/catalog/versions/v1.rs:1442
// TableDefinitionV1::add_columns — Vec::contains per tag column:
if matches!(column_type, InfluxColumnType::Tag) && !self.series_key.contains(&id) {
// O(K) scan where K = series key length
self.series_key.push(id);
}
add_columns checks self.series_key.contains(&id) for each new tag column, producing O(C x K) where C = columns being added and K = current series key length. During schema evolution with many tag columns, this becomes quadratic.
Complexity Proof
influxdb-0001: At T=1,000 existing files, F=500 new files per snapshot:
- Defective: 500 x 1,000 = 500,000 parquet file comparisons
- Fixed: 500 x 1 = 500 HashSet lookups
- 1,000x op reduction per snapshot load.
influxdb-0002: At K=100 series key columns, C=50 new tag columns:
- Defective: 50 x 100 = 5,000 ID comparisons
- Fixed: 50 x 1 = 50 HashSet lookups (with
insertreturning false for duplicates) - 100x op reduction per schema evolution.
Impact
InfluxDB powers time-series workloads across IoT, observability, and financial data pipelines. The persisted files defect (influxdb-0001) fires during WAL replay, snapshot loading, and compaction. High-write workloads that generate many parquet files per table compound the cost at every persistence boundary. The series key defect (influxdb-0002) fires during schema evolution, affecting workloads with dynamic tag sets (container orchestration metrics, multi-tenant IoT platforms).
The Fix
influxdb-0001: Build a HashSet<&str> of existing file paths for O(1) dedup:
// Before
.filter(|file| !table_files.contains(file)) // O(T)
// After
// CWE-407 fix: HashSet for O(1) dedup instead of O(T) Vec::contains.
let existing_paths: HashSet<&str> = table_files.iter().map(|f| f.path.as_str()).collect();
.filter(|file| !existing_paths.contains(file.path.as_str())) // O(1)
influxdb-0002: Pre-build a HashSet<ColumnId> from the series key:
// Before
if !self.series_key.contains(&id) { // O(K)
// After
// CWE-407 fix: HashSet for O(1) membership instead of O(K) Vec::contains.
let mut series_key_set: HashSet<ColumnId> = self.series_key.iter().copied().collect();
if series_key_set.insert(id) { // O(1), returns true if newly inserted
Patch
defects/influxdb/patch/influxdb-0001-persisted-files-dedup-quadratic.patch
defects/influxdb/patch/influxdb-0002-table-def-series-key-quadratic.patch
Unit tests: pass. influxdb-0001: 1,000x speedup at T=1,000 files. influxdb-0002: 100x speedup at K=100 columns.
What We Ask
- Confirm receipt and assign a GitHub issue reference (influxdata/influxdb).
- Validate patches against your write buffer and catalog test suites.
- Assess severity: influxdb-0001 fires on every snapshot load and file persistence event at scale.
- Coordinate a disclosure date: we target 90 days from first contact.
Contact: see cover email. This brief is confidential until coordinated disclosure.