Security News

Cybersecurity news aggregator

đź“°
INFO News Reddit r/netsec

How Codex found replayable state transitions and a lost-update race in a Supabase browser game

  • What: AI used to find vulnerabilities in a browser game
  • Impact: Demonstrates AI's role in security testing
Read Full Article →

How Many Exploits Does It Take to Turn an Egg into a Legendary Roc? I found a cute game about refusing birds. So I told Codex it was a CTF, and it stopped playing by the rules Shmulik Cohen | AI Superhero Aug 17, 2026 1 Share I discovered EggGame through a LinkedIn post, and I liked the idea immediately. There was an egg in the middle of the screen, a counter above it, and one wonderfully mean decision: hatch the bird being offered or refuse it forever in the hope that something better would appear. It was simple, cute, and exactly the kind of game I expected to play for a few hours before returning to whatever I was supposed to be doing. Instead, I handed the browser tab to Codex. The first request was harmless: “Can we get a stronger bird?” Then curiosity became ambition. I asked for the strongest bird ever, told Codex to continue until we were number one, and finally insisted that our bird defeat every other player and get all the upgrades. Somewhere during that escalation, the cute clicking game stopped being a distraction and became a security puzzle. Codex was no longer asking only how the game wanted us to progress. It was asking which assumptions the server would let us break. By the end, the original egg had become a tier-eight Roc with every stat at level 50, 4,183 power , 1,233 wins, and first place on the leaderboard. It also had 83,894 coins left, which was the suspicious part: the final four upgrades alone should have cost more than 332,000. Our path to the top had ignored the economy that the creator designed. The fun of the story is how an innocent egg, a stubborn agent, and a sequence of increasingly useful mistakes carried us there. EggGame is a small browser game built by Liad Ben Moshe . You tap an egg, hatch a bird, fight other players’ birds, earn coins, and spend those coins making yours stronger. In his launch post , Liad described its central tension beautifully: every offer tempts you to stop, while a stronger bird may still be waiting inside the egg. One correction matters: EggGame was not a CTF. I initially told Codex it was, and that framing encouraged the agent to treat every API endpoint as part of a challenge. Throughout the run, I kept the experiment inside ordinary player actions: no administrator access, no direct database changes, and no touching another player’s account. If Codex wanted a stronger bird, it had to find a mistake in something a normal player was allowed to do. Afterward, I spoke with Liad directly, explained what had happened, and shared everything we had found. Thanks for reading AI Superhero! Subscribe for free to receive new posts and support my work. Subscribe The leaderboard leaks the first clue Before Codex worked out how to hatch anything, it inspected the requests the browser was already making. The first surprise came from Supabase: the public client could read the entire profiles table. All 17 player rows were available, including UUIDs, balances, activity timestamps, persistent device identifiers, and the is_admin flag. The leaderboard needed only a small public view. The API returned the complete records. Writes were protected; reads were far too broad. The account-per-device limit had a related trust problem. Its “device ID” was a random UUID created by the browser and stored in localStorage . Clearing that storage, opening an incognito window, or supplying another value made the server see a new device. This is client-side trust in its purest form: a spoofable, client-controlled identifier used as the sole key for a server-side limit. These first findings did nothing to strengthen our bird. They changed the mood of the experiment. This cute game had a real backend, and the backend was making assumptions about what its browser could be trusted to say. The goal was still to reach number one, though, and the untouched egg was waiting. The egg keeps making better offers The first offer arrives after 50 taps: hatch now and receive a humble Chick. The other button lets you refuse it and keep tapping. Refusal is permanent: the Chick disappears forever, the egg cracks further, and the next threshold becomes a Sparrow at 150 taps. Continue refusing and the offers get wilder: Hawk at 400, Raven at 1,000, Griffin at 2,500, Phoenix at 6,000, Thunderbird at 14,000, and finally Roc at 33,000 taps. It is a lovely mechanic because the same button becomes harder to press. Refusing a Chick after 50 taps feels free. Refusing a Thunderbird after 14,000 feels reckless. Naturally, we refused all seven. Thirty-three thousand manual taps sounded like an excellent route to repetitive strain injury. The client offered a better path because it buffered progress and periodically called a sync-egg action. The server rejected a direct jump to 33,000, yet happily accepted another legal-looking chunk of roughly 50 taps without proving that fifty new taps had actually happened. No nonce, no sequence number, no timestamp check. Just: does this increment look reasonable? Codex...

Share this article