RSPS Vote Security: Lock Down Your Callback

The Endpoint Everyone Forgets
Vote callbacks are one of those things every RSPS has and almost nobody thinks about until something breaks. The flow looks simple enough on paper. A player votes on a toplist, the toplist pings your callback URL, your server hands out the reward, everyone goes home happy.
We have been running this list since 2002. In that time we have watched the same handful of mistakes wreck server after server, year after year. The attacks evolve a little, the tools get cheaper and more accessible, but the underlying problems on the server side stay almost identical. A new owner sets up a fresh server, points the callback at whatever default path their base shipped with, runs a couple of test votes to make sure rewards come through, and then never touches it again. Six months later they are trying to figure out why their economy collapsed overnight.
If you are running a server and you have not personally sat down with the vote flow recently, take this as your reminder. Do it before something forces you to.
How the Abuse Actually Works
There is nothing clever about most of it. Your callback URL is sitting on the public internet. If someone can figure out the path and the parameters it expects, they can hit it directly and skip the toplist entirely. Your server has no way to tell the difference. It processes the reward and credits the account.
On most setups we have seen in the wild, that is the whole attack. Curl in a loop, fake the parameters, collect rewards, repeat. We have come across servers where this had been running quietly for months before the owner noticed, because the rewards looked like normal voting activity in the database and nobody was reading the logs.
The more involved attacks build on the same idea. Replaying real callbacks captured from legitimate traffic. Hammering the endpoint with concurrent requests to exploit race conditions in the reward logic, so a single vote pays out three or four times before the database catches up. Brute forcing tokens that were never meant to be guessable but turned out to be predictable. None of this is new. We have been talking about these exact patterns with server owners for over twenty years and people still get caught by them.
What We Do Before the Callback Ever Reaches You
Before getting into the server side fixes, it is worth being explicit about what happens on our end, because that is half the equation and the half most owners do not have visibility into.
Every vote that lands on RSPS.org runs through multiple verification layers before any callback gets sent to your server. IP based deduplication catches repeat votes from the same network inside our window. Timestamp checks reject anything arriving faster than a human could actually click through. We screen against known bot signatures and the incentivized traffic patterns we have catalogued over the years. By the time a vote is considered valid on our side, it has already survived that gauntlet.
This is the part of the system we have put the most engineering work into, and we keep putting work into it. The voting landscape has shifted a lot since the early 2000s, attackers have better tooling, and we have kept the verification pipeline ahead of it because anything less would make the rankings meaningless. That commitment to keeping votes clean is the foundation everything else on the list is built on, and it is a big part of why server owners and players have stuck with us for as long as they have.
But our verification only protects what comes through us. If your callback endpoint is wide open to direct hits, all the filtering we do on the front end does not help you one bit. That part is on the server side, and that is what the rest of this article is about.
What a Properly Secured Callback Looks Like
There are a handful of things that need to be in place. Skip any of them and you are leaving the door open.
Validate that the request actually came from us. Every legitimate callback we send carries a verifiable signature or token tied to the specific vote. Your code needs to check it before doing anything else. If validation fails, reject the request immediately and log it. Do not return a helpful error message that tells the attacker what went wrong. Just close the connection and move on.
Confirm the vote actually exists on our end. This is what the callback verification system is for. Before crediting any reward, your server should be making a request back to us to confirm the vote ID is real, that it belongs to the username being credited, and that it has not already been processed. We built that pipeline specifically because we know what happens without it.
Enforce one reward per vote at the database level. This is the line most servers cross without realizing. The reward logic checks "has this user been rewarded for this vote" by querying the database, and if the query says no, it inserts a row and credits the reward. The problem is that if two callback requests arrive at the same millisecond, both queries return no, both inserts succeed, and the player gets rewarded twice. The fix is a unique constraint on the vote ID column in your rewards table. Database level, not application level. If a duplicate insert is attempted, the database rejects it and your code falls through cleanly. We have lost count of how many servers we have helped recover from race condition exploits that this one line of SQL would have prevented.
Rate limit the endpoint. Even with everything else in place, there is no reason for any single IP to be hitting your callback URL more than a few times per minute. Set a hard limit. Drop anything above it. This catches the brute force attempts before they become a real problem.
Log everything and actually read the logs. Every callback request, successful or not, should be logged with the IP, the timestamp, the parameters, and the outcome. We are still surprised how often we ask an owner who has been exploited to pull their callback logs and they tell us logging was never enabled. You cannot investigate what you did not record.
The Attack Most Owners Do Not See Coming
The exploits people usually worry about are the ones where an attacker farms their own account. Annoying, costly, but contained to one player. The attack that actually wrecks servers is different, and we see it often enough that it deserves its own section.
Someone with bad intentions does not need to limit themselves to their own username. If your callback accepts any username in the request, an attacker can spam vote rewards across every active player on your server. Pull the username list from your hiscores or your forum, write a script that hits your callback in a loop crediting each one, and within an hour every player on the server has received hundreds or thousands of vote rewards they never earned.
This is genuinely catastrophic. Not because the players did anything wrong, but because your economy is suddenly flooded with vote shop items, vote shop currency, or whatever else your rewards convert to. The market collapses overnight. Prices that took months to stabilize are gone in an afternoon. And unlike a single account being farmed, you cannot just roll back the offender, because the rewards are spread across the entire active playerbase.
The defense is exactly what you would expect but it is the part most servers get wrong. Voting needs hard limits that apply per account, not just per IP. A real player can vote once every twelve hours per toplist. That is the rule we enforce on our end and that is the rule your server side reward logic needs to be enforcing too. If your code accepts a callback crediting the same username twice inside that twelve hour window, something is already broken regardless of what the callback claims happened.
The check has to live in your code, not in trust of the incoming request. Before any reward is granted, query when the last vote reward for that username was processed. If it falls inside the legitimate voting cooldown, reject the request and log it. A player who can only legitimately receive a reward once every twelve hours can never end up with thousands of rewards in one minute, no matter what is being thrown at your endpoint. The math just does not allow it.
This single check, properly implemented at the application layer and backed by a unique constraint at the database layer, prevents the single most economically destructive attack vector on RSPS voting systems. The fact that it is still missing from a surprising number of production servers is the reason we keep writing about it.
The Database Side People Skip
Application code gets most of the attention in security discussions and the database side gets ignored, which is backwards. Your database is the source of truth. When your application logic has a bug, your database constraints are the last line of defense, and we have seen them save servers from disasters more times than we can count.
The rewards table needs a unique constraint on the combination of vote ID and any other identifier that should make a row unique. Foreign keys need to be enforced. Timestamps should be set by the database, not passed in by the application. If you let the application set the timestamp, anyone who finds an injection point can backdate or future date entries and break your entire audit trail.
The vote ID itself should be treated as untrusted input. We have seen servers blindly cast it to an integer and drop it straight into a query without sanitization. That is a SQL injection waiting to happen on an endpoint that was never authenticated in the first place. Parameterize every query. Always.
When You Suspect You Have Been Hit
If you find evidence of vote abuse, the instinct is usually to patch the hole and move on. That is the wrong order. Pull the data first. Query your rewards table for any account that has received an unusual volume of vote rewards in any short window. Cross reference against the legitimate vote records on our end if you are listed with us, because we keep our own logs and they will tell you which votes were real and which ones never actually existed.
Once you know the scope of what happened, decide how to handle the affected accounts. Some servers roll back, some take items out of the economy quietly, some ban outright depending on how much was taken. There is no universally right answer but doing nothing is wrong, because the players who voted legitimately are paying the cost of the inflated rewards through the economy whether they realize it or not.
Then patch. Then audit the rest of your endpoints, because if your callback was unprotected there is a very good chance something else is too.
A Note for Newer Owners
Most of the server owners we work with who end up hit by callback exploits are not bad developers. They are people who inherited a base, got the server running, focused on content, and never went back to look at the parts that already seemed to work. The vote system was one of those parts. Rewards came through, players were happy, no reason to dig into it.
We are telling you to dig into it anyway. It takes an afternoon to audit a vote flow properly. It takes weeks to recover from finding out someone has been farming yours, or worse, mass crediting your entire player base, for months.
If you want to see how serious servers handle the integration side of this, the RSPS list is a useful place to look. The ones holding their positions long term tend to be the same ones who took the time to set their callbacks up properly the first time, and the same ones who treat the voting relationship as something worth maintaining. The ones that show up, get hit, and disappear within a few months almost always had something basic broken on the security side. The pattern repeats every year and the lesson keeps being the same.
Find Your Next Server
Looking for a new RSPS to play? Browse our RSPS List to discover the best private servers, compare features, and find the perfect community for your playstyle.
More Articles You Might Enjoy
RSPSWhy RSPS Players Burn Out Faster Than They Expect
RSPS burnout happens quietly and faster than most players expect. This article explains burnout causes and why motivation fades even on good servers.
January 13, 2026

