← back

How Scores Were Faked in Drake's $10,000 Game Contest

Low Battery (RapTV's parent company) launched “Freeze The World” on icemancountdown.com to promote the release of Drake’s Iceman album. Stake.us sponsored a $10,000 prize to the user at the top leaderboard spot before the release.

Unfortunately, due to poor backend validation, attackers had the ability to submit fake scores without the need to even play the game.

Intended System Design

The game initializes a session by requesting a token from the server:

fetch("https://www.icemancountdown.com/api/runner-session-start", { "method": "POST", "body": "{}" }); // Returns: { ..."token": "...", "startedAt": {UNIX timestamp}... }

Once a token is issued, the server relies on the client to report the results of the run. In a legitimate run, once the player loses, their score (and other info) is passed onto the /api/runner-leaderboard endpoint to be submitted to the leaderboard.

Vulnerability

The server trusts the score and completion time the client submits without verifying that gameplay actually occurred.

This means that a bad actor could just manually construct this request via the browser console after obtaining a session token (via /api/runner-session-start) and submitting an arbitrary score value:

const forged = 999999; const myToken = "{token from /api/runner-session-start}"; const endTime = Date.now(); // (No, you cannot submit an endTime > Date.now()) fetch("https://www.icemancountdown.com/api/runner-leaderboard", { "method": "POST", "headers": { "Content-Type": "application/json" }, "body": JSON.stringify({ "name": "hacker123", "email": "hacker@gmail.com", "terms": true, "score": forged, "sessionToken": myToken, "gameEndedAt": endTime }) });

That’s all it takes to hold the top spot on the leaderboard.

Mitigation Attempt

The developers did implement a guardrail, though. The server maps the submitted token to that session’s startTime and subtracts the received endTime to obtain the elapsed time. It then checks if the proposed score is mathematically possible within the elapsed time.

The game uses a fixed TARGET_FPS = 60, and the score variable increments once per physics step. This means that the score increases by 60 points per second.

Therefore, we can say that:

score(t) = 60 x t

Upon defeat, function submitScore() sends a request to /api/runner-leaderboard, then the server calculates Scoremax using its own clock:

Scoreₘₐₓ = ((Tₑₙd - Tₛₜₐᵣₜ) / 1000) x 60

If the submitted score is greater than Scoreₘₐₓ, the server responds with error score_implausible.

Bypassing The Mitigation

This does not solve the vulnerability though. To bypass this check, an attacker would only need to age the session token. For example:

1. POST to /api/runner-session-start to obtain a session token. The server records Tₛₜₐᵣₜ (let’s say 1778783700074)

2. The attacker chooses a target score (let’s say 501,660) and calculates the minimum time needed to achieve that score (501,660 / 60 = 8631 seconds ≈ 2 hours, 24 minutes). They then wait for that duration.

3. The attacker sends a request to /api/runner-leaderboard via the console after waiting. Since the elapsed time justifies the score, the server will return {"status": "posted"}, and their submission will be visible on the leaderboard.

The plausibility check only enforces that the score is possible, but not if it was earned legitimately.

Conclusion

The leaderboard was filled with 999,999 scores from people who likely exploited this or a similar vulnerability.

Most were manually removed as the deadline got closer though, so hopefully the prize went to a legitimate participant.

This serves as a reminder why you should always practice adversarial thinking and assume people will try to break your system, no matter how simple that system may be.

I’m pretty sure that the game was vibe-coded anyways (evident by the AI-like comments throughout the code), which is fine, but it should have been reviewed.

This whole thing wasn’t really a big deal, but my boredom and curiosity warranted the analysis.