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.7 KiB
PgBouncer — CWE-407 Disclosure Brief (pgbouncer-0002)
2026-04-13 · Patch available — awaiting upstream merge
Finding
O(D) linear scan in find_database() where a linked list of all configured databases is traversed for every connection attempt. Replaced with an AA-tree index for O(log D) lookup.
The Defect
pgbouncer-0002 (PATCHED — MEDIUM): src/objects.c
PgDatabase *find_database(const char *name)
{
struct List *item, *tmp;
PgDatabase *db;
statlist_for_each(item, &database_list) {
db = container_of(item, PgDatabase, head);
if (strcmp(db->name, name) == 0)
return db;
}
// also searches autodatabase_idle_list
statlist_for_each_safe(item, &autodatabase_idle_list, tmp) {
db = container_of(item, PgDatabase, head);
if (strcmp(db->name, name) == 0) { ... }
}
return NULL;
}
find_database() fires on every new client connection. With D configured databases, each connection costs O(D) string comparisons. Multi-tenant deployments with hundreds of databases compound this for every connection in the pool.
Complexity Proof
At D=500 databases and C=10,000 connections per second:
- Defective: 10,000 × 250 (avg scan) = 2,500,000 string comparisons per second
- Fixed: 10,000 × log₂(500) ≈ 90,000 comparisons per second
- ~28× op reduction.
Impact
PgBouncer is deployed at scale in multi-tenant PostgreSQL environments (SaaS platforms, cloud database providers). Hundreds of configured databases with thousands of connections per second make find_database() a hot path. The AA-tree index mirrors the existing user_tree pattern already used for user lookup.
The Fix
Add a parallel AATree db_name_tree index alongside the existing database_list, maintained at add_database() time:
// Before — O(D) linked list scan:
statlist_for_each(item, &database_list) {
db = container_of(item, PgDatabase, head);
if (strcmp(db->name, name) == 0) return db;
}
// After — O(log D) AA-tree lookup:
node = aatree_search(&db_name_tree, (uintptr_t)name);
if (node) {
db = container_of(node, PgDatabase, name_tree_node);
return db;
}
Patch
Fix available: defects/pgbouncer-0002/patch/pgbouncer-0002.patch
Single-file patch in objects.c.
What We Ask
A patch is ready for review.
- Confirm receipt and assign a tracking reference (pgbouncer/pgbouncer).
- Assess severity — fires on every connection attempt, compounds with database count.
- Coordinate a disclosure date — we target 90 days from first contact.
- We will credit the PgBouncer team in the public disclosure. Preferred acknowledgment format welcome.
Contact: see cover email. This brief is confidential until coordinated disclosure.