← All work

Security

Finding the holes before a guest does

A live game and the tools that manage it were both trusting requests they had no reason to trust. Several of the actions could change live data in the database without proving who was asking.

3 high2 mediumAPI security testingAccess controlStaging reproduction

How the findings surfaced

I found these while building the Stadium Squares harness. A harness that exercises every game action will eventually call one it should not be allowed to call. I ran each suspicious case on staging, reproduced it, and wrote it down with its severity and its real-world impact. Each finding also became a test case that is expected to fail until the bug is fixed.

The game: anyone with a room code

A room code is shared with every player, so it is not a secret. These issues meant that anyone holding one could act as the host, or as another player.

SeverityFindingWhat an attacker could do
HighClosing a game needed no tokenEnd a live game in the middle of play. My test archived a real room.
HighUpdating a room's settings had no authorizationRewrite the prize table and the allowed win patterns, changing what players can win.
HighRevealing and expiring codes had no auth checkReveal a prize redeem code without staff approval, or expire it.
MediumWin acknowledgement had no ownership checkDismiss another player's win.
MediumThe event-simulation action needed no credential, including on productionCorrupt card pre-marking in a running game.

What this adds up to. Each of these is a write to live game data from a request that proved nothing about who sent it. At a venue, that means ended games, rigged prizes, leaked redeem codes, and angry guests. In a database, it means records you cannot trust after the fact.

Operators: one venue touching another

The venue app lets operators manage pods for their own venues. Testing the Pod feature showed that the boundary between venues was not enforced everywhere:

  • Content wipe. One pod action was not scoped to the operator's own venues. It returned success where its sibling actions correctly returned "forbidden", and it cleared another operator's content.
  • Locked out of your own venue. An operator could not create a variation for their own venue on a pod another operator had made, which left the tone unusable for everyone.
  • Possible takeover and name leak. I flagged two further risks as "possible": assigning venues might let one operator take over another's variation, and search might show names from hidden variations. A later permissions audit by a teammate confirmed both by reading the code. A cross-company takeover was not confirmed.

What I checked that held up

Good security testing also says what is fine. I verified the game's win calculation across the win types, and it was sound. The flaws were all in who is allowed to do what, not in the logic of the game.

A note on detail. I have left out endpoint names, request shapes, and reproduction steps on purpose. Some of these fixes are still in progress, and a public page is the wrong place for a recipe.