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

**Security contact:** github.com/Pylons/substanced/security/advisories/new

## Finding

One defect in SubstanceD's `Folder.reorder()` — quadratic scaling on folder item reordering. Patched. Patch ready for upstream review.

## The Defect

**substanced-0001 (PATCHED — MEDIUM):** `substanced/folder/__init__.py:169-173`

```python
# In Folder.reorder() — called to reorder M items in an N-item folder:
for name in names:
    if not name in order_names:          # O(N) scan
        raise FolderKeyError(name)
    idx = order_names.index(name)        # O(N) scan
    oid = order_oids[idx]
```

`order_names` is a plain Python `list` built from `self._order`. Per iteration: two O(N) linear scans — one membership check, one index lookup. With M items being reordered in a folder of N total items: **O(M×N)** total. When M is proportional to N (bulk reorder): **O(N²)**.

## Complexity Proof

**substanced-0001:** M reorder ops × two O(N) list ops: **O(M×N)**. At N=1,000 items: **2,000× op reduction** over the loop-based pair.

## Impact

SubstanceD is a CMS application framework built on Pyramid/ZODB. `Folder.reorder()` is called on UI drag-and-drop operations that reorder folder contents — a common CMS interaction. For large folders (content-heavy sites, media libraries, document repositories), worst-case complexity fires on every user reorder gesture.

## The Fix

**substanced-0001:** Pre-build name→index dict before the loop:

```python
# Before
for name in names:
    if not name in order_names:
        raise FolderKeyError(name)
    idx = order_names.index(name)

# After
# CWE-407 fix: pre-built dict for O(1) lookup instead of two O(N) list scans per item.
order_name_idx = {n: i for i, n in enumerate(order_names)}
for name in names:
    if name not in order_name_idx:
        raise FolderKeyError(name)
    idx = order_name_idx[name]
```

## Patch

Fix available: `defects/substanced/patch/substanced-0001-reorder-dict.patch`

Single-location patch in `substanced/folder/__init__.py`. Unit test: 1/1 pass. substanced-0001: **2,000×** op reduction at N=1,000.

## What We Ask

Patches are ready for review. Please open a GitHub Security Advisory at github.com/Pylons/substanced/security/advisories/new.

1. Confirm receipt and assign a tracker reference.
2. Assess severity — `reorder()` fires on every folder drag-and-drop in production.
3. Coordinate a disclosure date — we are targeting 90 days from first contact.
4. We will credit the SubstanceD team in the public disclosure. Preferred acknowledgment format welcome.

This brief is confidential until coordinated disclosure. Full report: https://undefect.com
