rpcs3 (4, C++), ppsspp (4, C++), spring-framework (3, Java), nats-server (3, Go), minio (3, Go), gimp (3, C), cockroach (3, Go), superset (3, Python). Note: rpcs3-0004 is CWE-312, rest are CWE-407.
5.5 KiB
Apache Superset — CWE-407 Disclosure Brief
2026-04-13 · Patches available — awaiting upstream merge
Finding
Three O(n²) defects in Apache Superset across the security manager builtin role initialization, dashboard native filter configuration, and dataset import metric/column dedup. All patched. Patches ready for upstream review. One defect fires during role permission setup; one fires during dashboard filter updates; one fires during dataset imports.
The Defects
superset-0001 (PATCHED — MEDIUM): superset/security/manager.py:1347
# In _get_pvms_from_builtin_role — fires during role permission setup:
role_from_permissions = []
for pvm_regex in role_from_permissions_names:
for pvm in all_pvms:
if re.match(view_name_regex, pvm.view_menu.name) and re.match(
permission_name_regex, pvm.permission.name
):
if pvm not in role_from_permissions: # O(R) list scan
role_from_permissions.append(pvm)
_get_pvms_from_builtin_role collects permission-view mappings matching regex patterns. The pvm not in role_from_permissions check does O(R) list scan (Python __eq__ comparison) for every match, inside an already-nested loop over regex patterns (P) and all PVMs (A). Total: O(P × A × R). With hundreds of PVMs and dozens of regex patterns, R grows toward P×A.
superset-0002 (PATCHED — MEDIUM): superset/daos/dashboard.py:422
# In update_native_filters_config — fires during dashboard filter updates:
for new_filter in attributes.get("modified", []):
new_filter_id = new_filter.get("id")
if new_filter_id not in [f.get("id") for f in updated_configuration]: # O(U) list rebuild
updated_configuration.append(new_filter)
The list comprehension [f.get("id") for f in updated_configuration] rebuilds a full list of filter IDs on every iteration of the new-filters loop. Total: O(M × U) where M = modified filters and U = accumulated updated filters. The list comprehension allocates a new list object each time.
superset-0003 (PATCHED — MEDIUM): superset/commands/dataset/importers/v0.py:161
# In import_datasource — fires during dataset import:
if imported_m.metric_name not in [m.metric_name for m in datasource.metrics]: # O(N) rebuild
datasource.metrics.append(imported_m)
if imported_c.column_name not in [c.column_name for c in datasource.columns]: # O(N) rebuild
datasource.columns.append(imported_c)
Both metric and column dedup loops rebuild a full list comprehension on every iteration — O(N²) total for N metrics and O(N²) for N columns. Each list comprehension allocates a new list and iterates all existing entries.
Complexity Proof
superset-0001: At P=20 regex patterns, A=500 PVMs, R growing to ~200 matches:
- Defective: 20 × 500 × 200 = 2,000,000 comparisons
- Fixed: 20 × 500 × 1 = 10,000 set lookups
- 200× op reduction.
superset-0002: At M=50 modified filters, U growing to ~100:
- Defective: 50 × (100 / 2) × list-rebuild = ~2,500 iterations + allocations
- Fixed: 50 × 1 = 50 set lookups
- 50× op reduction.
superset-0003: At N=200 metrics, N=200 columns:
- Defective: 200 × (200 / 2) = ~20,000 comparisons per import (metrics) + same for columns
- Fixed: 200 × 1 = 200 set lookups per import
- 100× op reduction.
Impact
Apache Superset powers business intelligence dashboards for thousands of organizations worldwide. superset-0001 fires during security role initialization — on every application startup and role sync, the security manager rebuilds permission sets for all builtin roles. Large deployments with hundreds of views and dozens of permission patterns compound the quadratic scan. superset-0002 fires during dashboard native filter updates — a common user workflow for dashboards with many cross-filters. superset-0003 fires during dataset imports, which are bulk operations for onboarding new data sources with many metrics and columns.
The Fix
superset-0001: Maintain a set() of PVM IDs alongside the result list for O(1) dedup.
# Before
if pvm not in role_from_permissions:
role_from_permissions.append(pvm)
# After — O(1) per check
if pvm.id not in role_from_permissions_ids:
role_from_permissions.append(pvm)
role_from_permissions_ids.add(pvm.id)
superset-0002: Maintain an updated_ids set, adding IDs as filters accumulate. Replace the list comprehension with a set membership test.
superset-0003: Pre-build existing_metric_names and existing_column_names sets before the import loops. Add names to the sets as new entries append.
Patch
Fixes available:
defects/superset/patch/superset-0001-security-manager-builtin-role-pvm-dedup.patchdefects/superset/patch/superset-0002-dashboard-filter-dedup.patchdefects/superset/patch/superset-0003-dataset-import-metric-column-dedup.patch
Three patches across superset/security/manager.py, superset/daos/dashboard.py, and superset/commands/dataset/importers/v0.py.
What We Ask
Patches ready for review.
- Confirm receipt and assign a GitHub issue reference (apache/superset).
- Assess severity — superset-0001 fires during role initialization; superset-0002 fires during dashboard filter updates; superset-0003 fires during dataset imports.
- Coordinate a disclosure date — we target 90 days from first contact.
- We will credit the Apache Superset team in the public disclosure. Preferred acknowledgment format welcome.
Contact: see cover email. This brief is confidential until coordinated disclosure.