Cap the number of inputs a transaction may spend (B-48)
select_utxos had no ceiling on input count, so an address fragmented into many small deposits built an ever-larger transaction whose fee — deducted from the amount being moved — eroded the bet's share of the pool or the withdrawn amount, and past a few hundred inputs stopped being standard at all. MAX_TX_INPUTS (50) now bounds the selection. Reaching the cap without covering the target is reported as its own "too_many_inputs" code, distinct from having no funds, with the cap carried in the error params for the 7 translations. The payout path records the same distinction in its payout_failed audit reason.
This commit is contained in:
@@ -1,11 +1,11 @@
|
||||
# Known bugs
|
||||
|
||||
A second full-codebase audit on 2026-07-27 found **25 further issues** (4 critical, 6 high,
|
||||
7 medium, 8 low), listed below as B-48 … B-49. B-25 through B-47 are fixed (see "Previously
|
||||
fixed" below) — no Critical-, High- or Medium-severity finding remains open; the remaining 2 are
|
||||
7 medium, 8 low), listed below as B-49. B-25 through B-48 are fixed (see "Previously
|
||||
fixed" below) — no Critical-, High- or Medium-severity finding remains open; the remaining 1 is
|
||||
Low/hygiene. The 139-test suite was green at the time of the audit, so none of these were caught
|
||||
by existing coverage — every fix lands with a regression test (the twenty-three fixes so far
|
||||
brought the suite from 139 to 248).
|
||||
by existing coverage — every fix lands with a regression test (the twenty-four fixes so far
|
||||
brought the suite from 139 to 251).
|
||||
|
||||
The recurring pattern across the open findings is worth stating once: the code is rigorous
|
||||
about the failure modes that have actually been hit, and silent about the ones that have not.
|
||||
@@ -18,14 +18,6 @@ admin auth, single-process assumptions, no user-facing history, etc.) are docume
|
||||
|
||||
## Low / hygiene
|
||||
|
||||
### B-48 — No cap on input count in `select_utxos`
|
||||
|
||||
A user with hundreds of small UTXOs builds a huge transaction whose fee — deducted from the bet
|
||||
amount — materially erodes their contribution to the pool, and it can exceed standardness
|
||||
limits.
|
||||
**Fix:** cap the selected inputs (e.g. 50) and fail with a translatable error suggesting a
|
||||
consolidation, or consolidate the address automatically when the count crosses a threshold.
|
||||
|
||||
### B-49 — Rollback paths do not publish an SSE update
|
||||
|
||||
`bets/service.py:_release_failed_bet` and `withdrawals/service.py:_release_failed_withdrawal`
|
||||
@@ -50,6 +42,7 @@ already does.
|
||||
- **B-44** — README's Quick start documented a bare `uvicorn --reload` workflow, and `docs/running-the-server.md` still had a matching "Locale / venv" section, both contradicting CLAUDE.md's Docker-only policy
|
||||
- **B-45** — `/admin/rounds`/`/admin/audit-log`'s `limit` had no bounds (`-1` means "everything" on SQLite), and `/admin/pending-transactions` had no limit or status filter at all
|
||||
- **B-46** — `secrets.compare_digest` on a `str` raises `TypeError` on non-ASCII input, turning an invalid admin token with non-ASCII characters into a 500 instead of a 403
|
||||
- **B-48** — `select_utxos` had no cap on input count, so a fragmented address built an ever-larger transaction whose fee (deducted from the amount being moved) ate into the bet or withdrawal, up to the point of being non-standard
|
||||
- **B-47** — `raw_tx_hex` and `payload_json` were unbounded `String` columns (`VARCHAR` with no length) — fine on SQLite/PostgreSQL, rejected by backends like MySQL that require a length
|
||||
- **B-32** — an RBF bump could retry forever below BIP125's relay-mandated minimum fee delta, with no ceiling on the fee rate either
|
||||
- **B-33** — `POST /auth/login` had no rate limiting, so a password could be brute-forced against an enumerable username list
|
||||
|
||||
Reference in New Issue
Block a user