# Podman — CWE-407 Disclosure Brief
**2026-03-27 · Patch available — awaiting upstream merge**

## Finding

Two O(n²) defects in Podman's Kubernetes translation layer and runtime pod tracking. Both use `slices.Contains` over growing slices in loops that iterate the same collection. Both patched. Speedups measured at 49×–50×.

## The Defects

**podman-0001 (PATCHED — HIGH):** `libpod/kube.go:1280`

```go
// determineCapAddDropFromCapabilities() — called per container during kube generate:
for _, cap := range containerCaps {                    // O(n) outer
    if slices.Contains(defaultCaps, cap) { ... }       // O(n) scan — cap-set diff
    if slices.Contains(otherCaps, cap)   { ... }       // O(n) scan
}
// O(n²) total — n = number of Linux capabilities in each set
```

`determineCapAddDropFromCapabilities()` computes the capability add/drop diff between container capabilities and default/other capability sets using `slices.Contains` inside a loop. For n capabilities per set: **O(n²)**. Fix: pre-build `map[string]bool` for `defaultCaps` and `otherCaps` before the loop → O(n). **Measured ratio: 50×.**

**podman-0002 (PATCHED — HIGH):** `libpod/runtime_pod.go:147`

```go
// GetRunningPods() — pod-ID dedup over container list:
for _, ctr := range allContainers {
    podID := ctr.PodID()
    if slices.Contains(pods, podID) {   // O(n) scan — n = pods accumulated so far
        continue
    }
    pods = append(pods, podID)          // growing slice — O(n²) total
}
```

`GetRunningPods()` deduplicates pod IDs by calling `slices.Contains` on the growing `pods` slice for each container. For C containers across P distinct pod IDs: **O(C × P)**. Since P grows toward C, worst case is **O(C²)**. Fix: `map[string]bool` for O(C) total. **Measured ratio: 49×.**

## Complexity Proof

**podman-0001:** Let n = number of Linux capabilities (typically 40+ for custom cap sets, up to ~60 defined in the kernel ABI).
- Defective: two `slices.Contains` calls per outer iteration → 2n comparisons per capability → 2n² total.
- Fixed: two `map[string]bool` lookups per iteration → O(2n) total (n to build each map + n lookups).
- At n=50 capabilities: defective=5,000 comparisons, fixed=100. **50× measured ratio.**

**podman-0002:** Let C = number of containers returned by the list, P = number of distinct pod IDs (P ≤ C).
- Defective: `slices.Contains(pods, podID)` where `pods` grows from 0 to P → 0+1+2+...+(P-1) = P(P-1)/2 comparisons → O(P²) ≤ O(C²).
- Fixed: `map[string]bool` → O(1) per check → O(C) total.
- At C=P=49 (49 containers, each in a distinct pod): defective=1,176 comparisons, fixed=49. **49× measured ratio.**

## Impact

podman-0001 affects `podman kube generate` — the command that translates Podman containers and pods into Kubernetes YAML manifests. This is a key migration and integration workflow for users moving workloads between Podman and Kubernetes. The defect fires once per container per `kube generate` invocation.

podman-0002 affects `GetRunningPods()` — a runtime function called by pod management operations including `podman pod ps`, `podman pod inspect`, and pod-aware container listing. It fires on every invocation in environments with many containers spread across many pods.

Podman is the primary rootless container runtime for RHEL/Fedora/CentOS and is widely used as a Docker alternative in security-sensitive environments.

## The Fix

**podman-0001:** Pre-build maps for both capability sets before the diff loop:

```go
// Before
for _, cap := range containerCaps {
    if slices.Contains(defaultCaps, cap) { ... }  // O(n) per cap
    if slices.Contains(otherCaps, cap)   { ... }  // O(n) per cap
}

// After
// CWE-407 fix: pre-built maps for O(1) cap lookup instead of O(n) slices.Contains.
defaultCapSet := make(map[string]bool, len(defaultCaps))
for _, c := range defaultCaps { defaultCapSet[c] = true }
otherCapSet := make(map[string]bool, len(otherCaps))
for _, c := range otherCaps   { otherCapSet[c] = true }

for _, cap := range containerCaps {
    if defaultCapSet[cap] { ... }  // O(1)
    if otherCapSet[cap]   { ... }  // O(1)
}
```

**podman-0002:** Replace the growing-slice dedup with a map:

```go
// Before
for _, ctr := range allContainers {
    podID := ctr.PodID()
    if slices.Contains(pods, podID) { continue }  // O(pods) per container
    pods = append(pods, podID)
}

// After
// CWE-407 fix: map[string]bool for O(C) dedup instead of O(C²) growing-slice scan.
seen := make(map[string]bool)
for _, ctr := range allContainers {
    podID := ctr.PodID()
    if seen[podID] { continue }  // O(1)
    seen[podID] = true
    pods = append(pods, podID)
}
```

## Patch

`defects/podman/patch/podman-0001-0002-kube-caps-pod-dedup-map.patch`

## What We Ask

1. Confirm receipt and assign a GitHub Security Advisory or issue reference (containers/podman).
2. Validate the patch against the kube generation and runtime pod test suites.
3. Assess CVE eligibility — both defects measured at 49×–50× under realistic workloads.
4. Coordinate a disclosure date — we are targeting 90 days from first contact.

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