Allusion
Security research, February 2026. Code on GitHub.
I pulled apart the game Rivals, a competitive shooter on Roblox, to find weaknesses in its anti-cheat, combat and rendering. I spent most of a school year on it, trying to see how much the game trusts the player's own machine. The short answer was too much.
Everything was reported to the developers before I made any of it public, and all of it was patched first. The repo is a record of the research, not something to run against the live game.
What I found
The anti-cheat could be reached from the client. The functions that report suspicious behavior were still sitting in the garbage collector where client code could find them, so a modified client could intercept its own reports before they were sent. A check that runs on the machine it's checking can be switched off by that machine.
Hit detection trusted a client-side raycast. Shots were resolved through a raycast in a shared utility module on the client. Redirecting that one function made a shot land on a target the camera wasn't pointed at, and the server accepted the result.
The wall check could be worked around. This was the hardest one. I rebuilt how the client handles item input and found that shifting the shot origin on the y-axis got past the check that's supposed to stop shooting through walls.
Body rotation was set by the client. The mechanics controller let the client decide which way its character faced on the server, without tripping the game's external flags.
Firing input could be automated. Nothing on the server told a real trigger pull apart from a scripted one.
The client knew where everyone was. Every player's position and health reached every client, even behind walls, so an overlay could draw boxes, health bars and skeletons for players you shouldn't be able to see.
The config also has an entry for a client-server desync, but I didn't publish code for it.
What it taught me
Almost every finding comes back to the same mistake. The server let the client tell it what happened instead of checking. Anti-cheat that lives on the player's machine slows people down but can't stop them, and the fixes that worked were the ones that moved a decision to the server.
Fixes I'd make
None of these need anything special. They move decisions off the player's machine.
- Check hits on the server. Recompute each shot from the server's own copy of each player's position and the shooter's view direction, with a lag allowance, and reject shots that don't line up.
- Treat client-side anti-cheat as a speed bump. It stops casual tampering, but anything running on the player's machine can be found and switched off.
- Compute the line of fire yourself. Work out the shot origin from where the player is and run the wall check on the server.
- Limit rotation on the server. Cap how fast and how far facing can change between updates.
- Look at input timing. Real trigger pulls are messy. If reaction times and shot intervals are too consistent, send the account for review.
- Only send what the player can see. If a client never receives the position of someone behind a wall, no overlay can draw them. Interest management costs some server work, but it closes the whole category.
Stack
The research build is Lua, with each finding behind its own toggle, plus a separate file for the anti-cheat work. The settings menu is built on LinoriaLib, which I didn't write.
Read the write-up on GitHub, or go back to mahfujmustafa.dev and the rest of my projects.