Saturday, August 1, 2026
Every operator route on the live service answered an anonymous request with a two hundred.
A user-interface review turned into a security session about ten minutes in. Pushing past the cosmetic findings to ask what else deserved a look surfaced that the public service was authorising nobody and serving everybody — including the routes that draw and settle a board. Fixed, verified in production, then swept every other live service for the same shape.
Shipped
- The operator interface was open to anyone — every operator route on the live service, plus the host routes that draw and settle a board, answered unauthenticated requests successfully. Now the absence of authentication configuration denies rather than permits: no config means a hard refusal, and opening it requires an explicit, exact-string override that must never live in the file the public service reads
- Swept every other live service for the same pattern — the rest of the estate came back clean, with one of them fail-closed by construction, not by intent
- Hosting needs an account; grabbing a line never does — creating, drawing and settling a board now requires being signed in, while the operator role stays on the operator area alone. Gating board creation on the operator role had meant exactly one person on earth could ever host a card, which is not a product
- The token names the caller, not the request body — ownership is read from the signed identity instead of a field the caller supplies, because a forgeable host field makes every ownership check theatre
- The games surface stopped being a four-oh-four — the whole lobby was missing from the public site, so nobody could have hosted anything even with the gate fixed. It ships now, listing real boards, with a board reachable by its own generated identifier
- Sign-in ships — the sign-in path dead-ended on the public build; it now reaches the identity provider and comes back cleanly
- A board locks itself at first pitch — locking runs ahead of the score fetch on the same schedule instead of as a separate task, so the two can't drift apart and no board is left an inning late
- Strip cards proven on a real finished game — settled a card against an actual completed baseball game and checked all three payout points against the real last digits. The game logic had been proven by hand and by nothing that runs on its own; there's now a test harness that does it every time
- The menu lists what ships — the sports menu advertised fifteen rows of which most were stubs; it lists five. The unbuilt routes stay reachable and self-explaining, they're just no longer advertised as if they were finished
- Score cards deep-link to a board — following a game's start-a-board link now opens the lobby with that sport and that matchup already selected, instead of an empty form
- A drift sweep across every repository — after noticing staging branches falling behind twice in one day, built a tool that checks all of them. The first run found eighteen drifted, one thirty commits behind, plus stale registrations and two apparent divergences. All the fast-forwardable ones are level and the whole estate is clean
- Two bugs in the tool itself, found by running it — it measured drift between remote branches then pushed the local one, which is routinely behind its own remote, so the server correctly rejected half the repositories. And it keyed on directory, not on remote, so repositories cloned twice were counted twice and one divergence was reported as two. Both fixed and documented in the code
- No terms or privacy links until the policies exist — linking them early would be a fabrication in the one place a reader takes the site completely literally. Recorded as a launch blocker, not a task
- A revenue router, written and open for review — a contract that splits incoming revenue three ways with the operating share capped in the contract itself, written tests-first with full coverage including fuzzed value-conservation. Open, not merged
Notes
Two things about the open operator interface are worth separating. The first is the defect itself, which is ordinary: authentication configuration was absent, and absent was being read as permitted. The second is why nobody caught it, which is not ordinary at all. The interface was never linked from the public site, so from the outside it didn't appear to exist — and "not linked" feels like a boundary right up until someone types the address. It had also passed a review earlier that noted the service restricts which origins a browser may call it from, which sounds adjacent to access control and is not: that mechanism tells a browser what it may do on behalf of a page, and it has no opinion whatsoever about a request that doesn't come from a browser. The correction to that note shipped alongside the fix, because a misleading comment in a deploy procedure is how a wrong idea gets inherited. Fail-closed is the only default that survives being forgotten: with it, a missing configuration produces a visible refusal; without it, a missing configuration produces a silent welcome.
