java-topology/whitepaper/outreach/minecraft.md
russell@unturf.com 0a580b313d undefect. CWE-407 — 63 sites patched across 27 ecosystems
Authors: russell@unturf.com · brackishbert@gmail.com · foxhop.net · TimeHexOn.com

Patches, unit tests, benchmarks, whitepaper, and outreach briefs.
Public domain — no copyright claimed. Use freely.
2026-03-26 17:11:57 -04:00

4.7 KiB
Raw Blame History

Minecraft / Mojang — CWE-407 Disclosure Brief

2026-03-26 · Confidential pre-disclosure

Finding

One exponential-complexity defect in Minecraft's tag dependency sorter. Unpatched. It causes StackOverflow during world load on large modpacks and produces measured 116× world load speedup when patched. We have benchmark data, a working patch, and a live demo.

The Defect

minecraft-0001 (UNPATCHED — CRITICAL): DependencySorter.javaisCyclic()

The isCyclic() method performs a recursive DFS to detect cycles in the tag dependency graph. It carries no visited set. Every node can be revisited an unbounded number of times.

On a diamond dependency chain of depth D (A → B,C; B → D; C → D), the recursion tree has no pruning:

  • Node D is visited once from B, once from C
  • Node at depth D-1 visits D twice each
  • Node at depth D-2 visits depth D-1 twice each
  • Total visits at depth D: 2^D

TagLoader calls this on every world load, for every tag group, for every namespace. This is not a degenerate edge case — it is the normal execution path for any modpack that uses tag inheritance.

Complexity Proof

Diamond chain of depth D: one root, branching factor 2 at each level, converging at each level (diamond, not tree). With no visited set, DFS re-explores both subtrees at every convergence point.

D Node visits
10 1,024
20 1,048,576
24 16,777,216
30 1,073,741,824

Vanilla Minecraft modpacks in the wild reach D=10-15 in large Forge/NeoForge packs. Our enriched benchmark runs D=24 with 300 namespaces.

Enriched benchmark result: vanilla server StackOverflows and fails to start. Patched server starts normally. World load time: 116× faster (patched vs. unpatched, measured at D=24/300NS). 30-player stress test with fireworks: patched server stable throughout; unpatched server hits unplayable lag before the StackOverflow.

For comparison, the two other defects found in the same codebase are minor:

  • minecraft-0002: PistonStructureResolver.javaList<BlockPos>.contains() in piston chain resolution. Bounded at 12 blocks max by game design. Not worth fixing.
  • create-0001 (Create mod): TrackGraph.java:findDisconnectedGraphsArrayList.remove(0) is O(n) shift in BFS frontier. Replace with ArrayDeque. Low severity, unbounded in theory but not hot in practice.

Impact

Every Minecraft server running a modpack with tag inheritance depth > ~15. Affected platforms:

  • Forge and NeoForge (primary modding platforms, millions of monthly active users)
  • Fabric (second-largest modding platform)
  • Any server hosting a tech modpack: Create, Applied Energistics, Thermal Expansion, etc.

The exponential is invisible at low D — vanilla Minecraft is mostly fine. It becomes catastrophic as modpacks grow. Large modpacks (1.19+, 300+ mods) are already at D values where world load takes minutes instead of seconds. At D=24 with namespace multiplier, vanilla StackOverflows entirely.

This is a serverside defect. It fires on every /reload, every server restart, every world load. Server operators and hosting providers running large modpacks are the primary affected population.

The Fix

Add a Set<Identifier> visited to the isCyclic() traversal. Return immediately if the current node has already been visited. This converts the exponential recursion to standard O(V+E) DFS.

// Before — exponential, no visited set
private boolean isCyclic(Identifier node, List<Identifier> path) {
    for (Identifier dep : getDependencies(node)) {
        if (path.contains(dep) || isCyclic(dep, path))
            return true;
    }
    return false;
}

// After — O(V+E), visited set prunes re-exploration
private boolean isCyclic(Identifier node, List<Identifier> path,
                          Set<Identifier> visited) {
    if (visited.contains(node)) return false;
    visited.add(node);
    for (Identifier dep : getDependencies(node)) {
        if (path.contains(dep) || isCyclic(dep, path, visited))
            return true;
    }
    return false;
}

One additional improvement: replace path.contains(dep) (also linear) with a LinkedHashSet<Identifier> for the path itself — O(1) cycle detection for the ancestor check as well.

What We Ask

  1. Confirm receipt and assign a tracker reference (bugs.mojang.com or internal).
  2. Assess severity — this is a StackOverflow / DoS on world load for large modpacks, reproducible and benchmarked.
  3. We have a working patch and benchmark harness available on request.
  4. Coordinate a disclosure date — we are targeting 90 days from first contact.
  5. We will credit Mojang in the public disclosure. Preferred acknowledgment format welcome.

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