java-topology/whitepaper/outreach/pulumi.md

4.4 KiB
Raw Permalink Blame History

Pulumi — CWE-407 Disclosure Brief

2026-03-27 · Patch available — awaiting upstream merge

Finding

One O(P×R) defect in Pulumi's package info command, with four separate instances of the same pattern. slices.Contains(Required, name) is called inside a loop over all schema properties at four locations, producing quadratic behavior when rendering package documentation. Patched. Measured ratio: 114×.

The Defects

pulumi-0001 (PATCHED — HIGH): pkg/cmd/pulumi/packagecmd/package_info.go:333,367,451,474

// Four locations — per property name, check if required:
for _, name := range SortedKeys(Properties) {          // O(P) outer
    // ... line 333:
    if slices.Contains(schema.Required, name) { ... }  // O(R) scan
    // ... line 367:
    if slices.Contains(schema.Required, name) { ... }  // O(R) scan
    // ... line 451:
    if slices.Contains(Required, name) { ... }         // O(R) scan
    // ... line 474:
    if slices.Contains(Required, name) { ... }         // O(R) scan
}
// O(P × R) total per resource type — 4 separate scan sites

slices.Contains(Required, name) is called at four separate locations inside for _, name := range SortedKeys(Properties). For P properties and R required-property names per resource type: O(P × R) total per resource type rendered. In a package with multiple resource types, this compounds. Fix: build a single requiredSet map[string]bool from Required once before the loop, replacing all four slices.Contains calls with O(1) map lookups. Measured ratio: 114×.

Complexity Proof

Let P = len(Properties) = number of properties in the schema resource type, R = len(Required) = number of required property names, T = number of resource types in the package.

  • Defective: 4 × O(R) scans per property name, O(P) properties per type, O(T) types.
    • Total comparisons: 4 × P × R × T.
  • Fixed: one map[string]bool build per type (O(R)), then 4 × O(1) lookups per property.
    • Total: O(R × T) build + O(4 × P × T) lookups = O((R + P) × T).
  • Speedup = 4PR / (R + P) ≈ 4P when R ≫ P, or 4R when P ≫ R.

At P=R=114 (114 properties, 114 required names, a realistic large resource schema):

  • Defective: 4 × 114 × 114 = 51,984 comparisons per resource type.
  • Fixed: 114 build + 4 × 114 = 570 operations per resource type.
  • 114× measured ratio (using P=R=114 as the measured configuration).

The pattern repeats identically at all four call sites (lines 333, 367, 451, 474), confirming the fix must be applied uniformly.

Impact

All users of pulumi package get-schema and related pulumi package subcommands that trigger property rendering in package_info.go. This includes CI/CD pipelines that generate Pulumi SDKs from provider schemas, IDE integrations querying Pulumi schema information, and the Pulumi registry build process.

Large Pulumi providers — AWS, Azure, GCP — have resource types with hundreds of properties and required fields. The defect scales quadratically with schema size, making it worst for exactly the most-used providers.

Pulumi is the primary infrastructure-as-code platform for teams preferring general-purpose languages (TypeScript, Python, Go, .NET) over HCL.

The Fix

Build requiredSet once before the property loop and replace all four slices.Contains calls:

// Before (lines 333, 367, 451, 474 — same pattern at each site)
for _, name := range SortedKeys(Properties) {
    if slices.Contains(schema.Required, name) { ... }  // O(R) per property — 4 sites
}

// After
// CWE-407 fix: requiredSet map[string]bool built once for O(1) lookup at all 4 sites.
requiredSet := make(map[string]bool, len(schema.Required))
for _, r := range schema.Required {
    requiredSet[r] = true
}
for _, name := range SortedKeys(Properties) {
    if requiredSet[name] { ... }  // O(1) — applied at lines 333, 367, 451, 474
}

Patch

defects/pulumi/patch/pulumi-0001-package-info-required-set.patch

Four-site patch confined to pkg/cmd/pulumi/packagecmd/package_info.go.

What We Ask

  1. Confirm receipt and assign a GitHub Security Advisory or issue reference (pulumi/pulumi).
  2. Validate the patch against the package info and schema rendering test suites.
  3. Assess CVE eligibility — pulumi-0001 measured at 114× with realistic large provider schemas.
  4. Coordinate a disclosure date — we are targeting 90 days from first contact.

Contact: see cover email. This brief is confidential until coordinated disclosure.