Lesson 10: Cheat and Abuse Surface Triage - Server Validation and Rate Limits

Most early multiplayer slices fail security in the same way: they trust client intent too much.

The goal for this lesson is not to build enterprise anti-cheat. It is to stop the highest-impact abuse patterns before your first external playtest.

Lesson objective

By the end of this lesson, you will have:

  1. A small cheat-surface inventory for your current slice
  2. Server-side validation for high-risk gameplay actions
  3. Basic per-action rate limits to block spam abuse
  4. A triage rubric for go/no-go playtest decisions

Why this matters now

You already have headless smoke infrastructure from Lesson 9.
Now you need to ensure the server does not accept impossible state changes from modified clients or replay spam.

Fixing these issues early prevents:

  • progression corruption during playtests
  • unfair matches that invalidate feedback
  • noisy bug reports caused by obvious exploit paths

Step-by-step triage pass

Step 1 - Build an abuse surface list

List every client-originating action that mutates important state:

  • damage apply
  • item pickup or currency grant
  • objective completion signal
  • movement mode toggles
  • match flow actions (ready, start, vote, restart)

Mark each action by impact:

  • Critical: breaks match integrity
  • High: gives major unfair advantage
  • Medium: annoys or destabilizes session
  • Low: cosmetic or low-impact misuse

Prioritize only Critical and High in this lesson.

Step 2 - Enforce authority checks on server handlers

For each critical action, verify:

  1. caller identity is known and authenticated in-session
  2. caller is allowed to perform this action
  3. target state transition is legal in current game phase

Never trust client-side prechecks as final authority.

Step 3 - Validate payload boundaries

Before applying server mutations, validate payloads:

  • numeric bounds (damage, speed, stack size)
  • enum allow-lists (action type, ability IDs)
  • object ownership (requested target belongs to expected context)
  • timing constraints (cannot trigger before cooldown or phase unlock)

Reject invalid payloads and log compact reason codes for analysis.

Step 4 - Add lightweight action rate limiting

Implement a simple per-client token bucket or cooldown map for abuse-prone actions:

  • fire/use ability RPCs
  • inventory transfer RPCs
  • session flow requests

You are not trying to perfectly classify intent. You are preventing abuse bursts that can melt slice stability.

Step 5 - Define enforcement outcomes

Use clear outcomes for violations:

  • warn: first suspicious event
  • drop_action: invalid payload or exceeded rate
  • flag_session: repeated abuse pattern
  • kick_client: severe repeated integrity failures

Keep this policy explicit so QA and design understand enforcement behavior during tests.

Example - server-side action guard

using Unity.Netcode;
using UnityEngine;

public class CombatActionGuard : NetworkBehaviour
{
    [ServerRpc(RequireOwnership = false)]
    public void RequestAttackServerRpc(int abilityId, float claimedDamage, ServerRpcParams rpcParams = default)
    {
        ulong sender = rpcParams.Receive.SenderClientId;

        if (!IsValidAbility(abilityId))
        {
            Debug.LogWarning($"ANTIABUSE drop_action reason=invalid_ability sender={sender}");
            return;
        }

        if (claimedDamage < 0f || claimedDamage > 250f)
        {
            Debug.LogWarning($"ANTIABUSE drop_action reason=damage_out_of_range sender={sender}");
            return;
        }

        if (!CanActNow(sender, abilityId))
        {
            Debug.LogWarning($"ANTIABUSE drop_action reason=rate_limited sender={sender}");
            return;
        }

        ApplyAuthoritativeAttack(sender, abilityId, claimedDamage);
    }

    private bool IsValidAbility(int abilityId) => abilityId >= 0 && abilityId <= 12;
    private bool CanActNow(ulong sender, int abilityId) { return true; }
    private void ApplyAuthoritativeAttack(ulong sender, int abilityId, float claimedDamage) { }
}

This is intentionally lightweight. Expand later with replay detection and deeper behavioral telemetry.

Mini challenge

Create an abuse-triage.md sheet with:

  1. five client-originating actions
  2. impact rating for each
  3. current validation status (missing, partial, done)
  4. one concrete mitigation per missing item

Then implement two highest-risk mitigations before your next playtest build.

Pro tips

  • Keep anti-abuse logs compact and structured for quick filtering.
  • Attach a build_id to enforcement logs so regression tracking is easier.
  • Prefer deterministic rejection over hidden correction for debugging clarity.

Common mistakes

  • Validating on client but not on server.
  • Trusting claimed values (damage, distance, currency) without server recompute or bounds checks.
  • Adding aggressive kick logic before observability exists.

Troubleshooting

"Legit players get rate-limited during normal combat."

Increase burst allowance or separate limits by action class so core gameplay is unaffected.

"Cheat reports are vague and hard to reproduce."

Add reason codes and sender IDs in logs, then compare against session timeline.

"Server validation causes desync complaints."

Ensure client prediction displays pending state and reconciles gracefully on rejection.

FAQ

Do I need third-party anti-cheat now?

No. For a vertical slice, strong server validation and sane rate limits provide most of the immediate value.

Should we instantly ban abusive clients in playtests?

Usually no. Start with logging + action drops, then escalate once patterns are confirmed.

How often should triage be rerun?

Every time new networked gameplay actions are added or modified.

Recap

You now have a practical anti-abuse baseline: identify high-impact surfaces, validate on server, and rate-limit spam-prone actions.

Next lesson teaser

Lesson 11 moves into profiling with networking counters so you can correlate bandwidth, tick behavior, and GC spikes with real multiplayer sessions.

Related links

Run this triage before every friends-and-family drop. Fairness and stability are core to trustworthy multiplayer feedback.