Backend Engineering • Anti-Cheat

Secure Leaderboards with Firebase: The Anti-Cheat Guide

Written by Sudhishkumar K • Updated May 2026 • 20 Min Read

Every game developer knows the pain. You spend 12 months building a beautiful, balanced puzzle game. You launch it on the Play Store, go to sleep, and wake up to find the #1 spot on the leaderboard is held by "Hacker123" with a score of 9,999,999,999.

A hacked leaderboard doesn't just look bad; it destroys the motivation of your legitimate players. Why should they grind to improve their skill if the top spots are mathematically impossible to reach?

The hard truth is: If you trust the client, you have already lost. In this guide, we will move from the "Naive" implementation that most tutorials teach, to a "Fortified" architecture using Firebase Cloud Functions, Heuristic Validation, and Shadow Banning.

1. Know Your Enemy: How They Cheat

To stop a hacker, you must think like one. There are three main ways players break mobile game leaderboards:

Attack Method How It Works The Solution
Memory Editing Using tools like Cheat Engine or GameGuardian to find the integer `currentScore` in RAM and change it to 99999 before the level ends. Obfuscated Types (Memory Protection).
Packet Sniffing Using tools like Wireshark or Charles Proxy to intercept the HTTP request sending the score and modifying the JSON payload. HTTPS + Server-Side Validation.
API Replay Decompiling your APK, finding your Firebase API keys, and writing a script to send fake "Write" requests directly to your database. Cloud Functions (Remove Write Access).

2. Defense Layer 1: Memory Obfuscation

Before the data even leaves the phone, we must ensure it hasn't been tampered with in RAM. If you define your score like this:

public int score;

You are making it trivial for memory scanners to find. They search for "10", collect a coin, search for "20", and boom—they have the memory address.

Use a simple XOR obfuscation wrapper (or a plugin like Anti-Cheat Toolkit). Here is a simple implementation you can write yourself:


public struct SafeInt {
    private int hiddenValue;
    private int key;

    public SafeInt(int value) {
        key = UnityEngine.Random.Range(100, 99999);
        hiddenValue = value ^ key; // XOR encrypt
    }

    public int GetValue() {
        return hiddenValue ^ key; // XOR decrypt
    }

    public void SetValue(int value) {
        key = UnityEngine.Random.Range(100, 99999); // New key every time
        hiddenValue = value ^ key;
    }
}
            

Now, the value in RAM changes wildly every time it is updated, making it invisible to simple scanners.

3. Defense Layer 2: Cloud Functions (The Gatekeeper)

This is the most critical step. Revoke all write access to your leaderboard collection in Firestore Security Rules.


// firestore.rules
service cloud.firestore {
  match /databases/{database}/documents {
    match /leaderboard/{userId} {
      allow read: if true;
      allow write: if false; // NO WRITES FROM CLIENT!
    }
  }
}
            

"But Sudhish, how do I save the score?"
You don't. You call a Cloud Function. The client submits the result of the game, and the Server decides if it is valid, and then the Server writes to the database.

[Image of Client-Server Architecture Diagram]

The "Heuristic" Validation Strategy

Don't just send the score. Send the metadata of the run.
Bad: { score: 5000 }
Good: { score: 5000, duration: 120, enemiesKilled: 50, levelId: 3 }

Now, inside your Cloud Function (Node.js), you can write logic to catch liars.


// index.js (Firebase Cloud Function)
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();

exports.submitScore = functions.https.onCall((data, context) => {
    if (!context.auth) return { status: "error", message: "Not Logged In" };

    const { score, duration, enemiesKilled } = data;
    
    // VALIDATION 1: The "Speedrunner" Check
    // If they got 5000 points in 10 seconds, it's fake.
    const maxPossibleScorePerSecond = 10; 
    if (score > duration * maxPossibleScorePerSecond) {
        console.warn(`Cheater detected: ${context.auth.uid}`);
        return { status: "rejected" };
    }

    // VALIDATION 2: The "impossible" Check
    // If the level only has 40 enemies, you can't kill 50.
    if (enemiesKilled > 40) {
        return { status: "rejected" };
    }

    // If valid, write to Firestore (Server has admin privileges)
    return admin.firestore().collection('leaderboard').doc(context.auth.uid).set({
        score: score,
        username: context.auth.token.name || "Anonymous",
        timestamp: admin.firestore.FieldValue.serverTimestamp()
    });
});
            

4. Defense Layer 3: HMAC Signing

If Cloud Functions are too expensive (or you want to verify the data integrity before it even reaches the cloud), you can use HMAC (Hash-Based Message Authentication Code).

The idea is simple: You have a secret key in your game (Note: Unity code can be decompiled, so this isn't bulletproof, but it stops script kiddies). You hash the score with the key.

Hash = SHA256(Score + SecretKey)

When the server receives the score and the hash, it recalculates the hash itself. If the hash the client sent doesn't match the hash the server calculated, the user modified the packet in transit.

5. The Ultimate Weapon: Shadow Banning

What do you do when you detect a cheater?
Option A: Ban them immediately. (Bad. They will just make a new account and try harder).
Option B: Shadow Ban them. (Genius).

When your Cloud Function detects a cheater, do not reject the score. Instead, save a flag on their user profile: isCheater: true.

Then, in your Unity client, when you request the leaderboard data:

The cheater sees their high score on the list. They think they succeeded. They see other cheaters on the list. They have no idea they are playing in a quarantine zone, separated from the real community. This wastes their time and protects your honest players.

Conclusion

Security is an arms race. You will never stop 100% of hackers. If a state-sponsored hacker wants to break your mobile puzzle game, they will.

However, your goal is not perfection; it is deterrence. By moving logic to Cloud Functions, obfuscating memory, and implementing heuristic checks, you make cheating tedious and difficult. Most hackers are lazy—they will give up and move on to an easier target.


Frequently Asked Questions (FAQ)

Q: Are Cloud Functions free?
A: Firebase Cloud Functions require the "Blaze" (Pay As You Go) plan. However, the free tier is generous (2 million invocations per month). For most indie games, it is effectively free.

Q: Can I use Realtime Database instead of Firestore?
A: Yes, the concepts are identical. However, Firestore allows for easier complex querying (e.g., "Top 50 scores where country == 'India'"), which is harder to do in Realtime Database.

Q: What if I have an offline single-player game?
A: If your game is offline, you cannot stop cheating. The user owns the device. You can only validate the score once they reconnect to the internet.