I lost mogoff after mogoff. I'm not going to pretend I handled it well. It was the lightnings fault for sure…

I sat there for a second, genuinely convinced something was off. The site felt vibecoded — you know that feeling when you look at a product and can just tell the architecture is vibes all the way down? I'd never been poking around omoggle before out of curiosity, but this time I had motivation. I opened Burp Suite.

What's omoggle

For context: omoggle is a platform where you go 1v1 with a stranger on camera in short video battles called "mogoffs." You win, you gain ELO. You lose, you drop. There's a leaderboard. People genuinely care about their ranking. The site even has some anti-cheat built in — more on that in a second.

Finding the request

I started watching the HTTP history at the end of a match. Right as the mogoff concluded, a POST request fired to /api/match/finalize. It contained the match result — including my score, my opponent's score, a score cap, and a whole selfScanValidity block full of face detection metrics: facePresentRatio, landmarkStability, blinkOrExpressionEvidence, and more.

That last part is interesting. The developers clearly thought about integrity. They had the client report whether your face was actually present and stable during the match, presumably to catch people going AFK or covering their camera. The anti-cheat logic existed. It just didn't matter, because the score was still coming from the client.

The problem was that /finalize fired fast. Like, I couldn't manually intercept and edit it in time — the request was already gone before I could touch it in Burp's proxy. So I did what you do: I went to Match and Replace and set up three regex rules to automatically rewrite the outgoing body before it ever left my machine:

Match: "selfScore":\d+(\.\d+)?      →   Replace: "selfScore":9.3
Match: "scoreCap":\d+(\.\d+)?       →   Replace: "scoreCap":10
Match: "opponentScore":\d+(\.\d+)?  →   Replace: "opponentScore":5
None

Enabled. Done. No more manual interception needed.

From that point on, every match I played, Burp silently rewrote the finalize request before it hit the server. The server accepted it. No validation. No cross-check. It just processed whatever I sent and updated the ELO accordingly — eloResolved: true, every time.

I won. Constantly.

What the response looked like

The server's response confirmed the whole thing was working exactly as intended (from my perspective, anyway):

None

Every match, ELO going up. The server was fully convinced I was winning legitimately.

This is a textbook client-side trust issue. The server accepted the match result as reported by the client, rather than computing it independently.

What makes it worse is that the scaffolding for a better system was already there. The selfScanValidity block shows the developers were thinking about what the client reports and whether it can be trusted. But that logic was applied to the wrong thing — face presence data that doesn't affect the score — while the score itself was left completely open.

A properly implemented finalize endpoint would either:

  • Accept only a match/session ID and compute the result server-side from data it already has, or
  • Validate any client-submitted score against its own authoritative record

One check. That's the whole fix.

Disclosure

After sitting on it for a bit and confirming it worked consistently, I reached out via the platform's Discord bugs channel. I kept it vague at first — said I'd found something affecting match integrity, asked if they had a bounty process. The head dev (Ben) responded quickly, confirmed they were already aware the architecture wasn't great and were working on it, and gave me the green light to write this up.

Closing thoughts

I found this bug because I lost and couldn't accept it. That's it. That's the whole origin story.

But here's the thing — my suspicion wasn't wrong, it was just misdirected. The outcome was manipulable. Just not by whoever mogged me. By anyone with Burp Suite and five minutes.

The lesson isn't new: never trust the client. Score calculation belongs on the server. Always. The face detection anti-cheat was a good instinct pointed at the wrong layer of the stack.

Also I did end up winning a lot of mogoffs. So.

Vulnerability reported May, 2026. Patched by the development team. Writeup published with explicit permission