All projects with patches now have outreach docs. 276 new docs covering CWE-407, CWE-312, CWE-362 across C, C++, Java, Python, Go, Rust, C#, PHP, Ruby, JavaScript, Dart, Erlang, R, and more. Outreach gap: 276 -> 0.
2.8 KiB
KataGo — CWE-407 Disclosure Brief (katago-0001)
2026-04-13 · Patch available — awaiting upstream merge
Finding
One O(Nk) defect in KataGo's liberty counting. The Board::findLiberties() method uses a linear scan over a buffer for duplicate liberty detection, producing O(Nk) total cost where N = chain size and k = accumulated liberties. Called 25,000+ times per ladder search.
The Defect
katago-0001 (PATCHED — HIGH): cpp/game/board.cpp:1437
int Board::findLiberties(Loc loc, vector<Loc>& buf, int bufStart, int bufIdx) const {
// For each stone in chain:
for(int i = 0; i < 4; i++) {
Loc lib = cur + adj_offsets[i];
if(colors[lib] == C_EMPTY) {
// Check for dups — O(k) linear scan
bool foundDup = false;
for(int j = bufStart; j < bufIdx+numFound; j++) {
if(buf[j] == lib) { foundDup = true; break; }
}
}
}
}
For each stone in a chain of size N, each adjacent liberty candidate triggers a linear scan of all previously found liberties (up to k). Total cost: O(N*k) where k grows to O(N) for scattered groups.
Complexity Proof
At chain=100 scattered stones:
- Defective: 100 stones × ~50 avg liberties = 5,000 comparisons per call × 25,000 calls/search = 125M comparisons
- Fixed: 100 stones × O(1) bitset lookup = 100 per call × 25,000 = 2.5M operations
- ~50× op reduction per call. At 25,000 calls per ladder search, total savings compound.
Impact
KataGo is the strongest open-source Go engine, used by professional Go players, researchers, and online Go servers worldwide. Liberty counting fires thousands of times per move during ladder reading and life-and-death analysis. The quadratic cost compounds in deep tactical searches.
The Fix
Replace the linear dup scan with a stack-allocated bool seen[MAX_ARR_SIZE] bitset indexed by board coordinate:
// After — O(1) bitset lookup per candidate liberty
bool seen[MAX_ARR_SIZE] = {};
for(int j = bufStart; j < bufIdx; j++) seen[buf[j]] = true;
// ... in loop:
if(colors[lib] == C_EMPTY && !seen[lib]) {
buf[bufIdx+numFound] = lib;
seen[lib] = true;
numFound++;
}
Patch
Fix available: defects/katago/patch/katago-0001-findliberties-bitset.patch
Single-file patch in cpp/game/board.cpp. Stack-allocated bitset (<=931 bytes). ~50× speedup per findLiberties call at chain=100.
What We Ask
A patch is ready for review.
- Confirm receipt and assign a GitHub issue reference (lightvector/KataGo).
- Assess severity — fires 25,000+ times per ladder search, quadratic in chain size.
- Coordinate a disclosure date — we are targeting 90 days from first contact.
- We will credit the KataGo team in the public disclosure. Preferred acknowledgment format welcome.
Contact: see cover email. This brief is confidential until coordinated disclosure.