skip to content

A game client computes currency balances locally and reports totals to your server — how do you threat-model it?

level: seniorimportance: must knowfreq 65%

answer

  1. Who owns the hardware?
  2. The account holder is the attacker
  3. Check exists twice, for different reasons
  4. Send intents, not totals
  5. Hardening delays; it does not enforce

basics

~20 s

Put the trust boundary between the device and your API. Anything the client computes is an assertion, not a fact, so the server must re-derive the balance from state it holds. The client-side calculation is user-experience, not a control.

solid answer

~50 s

I draw the trust boundary at the network edge of my service: the client process runs on hardware the player owns, so it is outside my boundary and everything crossing that boundary is attacker-controlled input. The attacker worth modeling here is the paying user running a modified build, not an anonymous outsider — that changes which threats matter. In STRIDE terms the dominant threat is Tampering with the reported total (an integrity violation), with Elevation of Privilege close behind if the total unlocks entitlements nobody paid for. The fix is structural rather than defensive: the client should send *intents* ("I completed this match"), and the server should apply the economy rules against its own authoritative event history and return the resulting balance. The local computation stays, because instant feedback and fewer round trips are real UX value — but it is a display hint. Client hardening raises attacker cost; it never moves the boundary.

go deeper

for a junior

Be ready to state the rule plainly: anything computed on a device the user controls can be changed by that user, so the server must decide. Know that a disabled button is not a permission check.

for a middle

Explain the mechanics: where the trust boundary sits on the diagram, why the same check legitimately exists on both sides for different reasons, and how an API of verbs beats an API that accepts a final total.

for a senior

Show production judgment by naming the account holder as the attacker, mapping the threats to integrity and authorization, and describing what you do when full server re-derivation is too expensive — invariants, rate bounds, reconciliation, and a hard check at cash-out.

for a principal

Own the tradeoff: how much fraud the economy can absorb, what client hardening is worth as a delay control against its engineering and release cost, and how you decide which irreversible steps deserve synchronous verification.

## The situation A free-to-play game ships a client that tracks a player's in-game currency and cosmetic entitlements locally, then posts totals to the server, which stores them. The design is fast and cheap. It is also unenforceable, and the way to show that in an interview is to model it rather than to assert it. ## Where the boundary goes On a data-flow diagram, the game client is a process running in a trust zone you do not control. The player owns the hardware and the operating system on it. They can attach a debugger, patch the binary, intercept and edit the request before it leaves, or skip the client entirely and speak to your API directly. So the trust boundary is drawn at your service's network edge, and every flow crossing inward is attacker-controlled input — including flows your own code emitted. The boundary faces one way that people often get backwards. It does not protect the client from you; it protects your service from the client. Nothing you place on the far side of it — a check, a constant, a secret, a validation rule — is protected by being there. ## The attacker position that gets missed Most threat models default to an anonymous outsider trying to steal customer data. Here the attacker is the legitimate, authenticated, possibly paying customer, and the asset is money and the integrity of the game economy. That single change reorders the whole model: Information Disclosure barely matters (the player is looking at their own data), while Tampering and Elevation of Privilege dominate. A model that never considers the account holder as an adversary will pass review and still miss the actual threat. ## "Client-side check as UX, not control" The same check often exists twice, for two different reasons, and confusing them is the classic defect: - **On the client:** immediate feedback, responsiveness while offline or on a bad connection, fewer round trips, less server load. Removing it makes the product worse. - **On the server:** the control. Removing it removes the security property. The test is simple: if an attacker deletes or edits the client-side check, what still stops them? If the answer is "nothing", the check was never a control. Grey-out buttons, disabled menu items, hidden admin screens and locally computed prices all fall into this category. ## STRIDE reading - **Tampering** — the reported total is modified in transit or at source; violates integrity. - **Elevation of Privilege** — the modified total grants entitlements the player is not authorized to hold; violates authorization. - **Spoofing** — relevant only if the client asserts *who* it is rather than proving it; violates authentication. - **Repudiation** — a secondary but real consequence: with no server-side derivation, you cannot later distinguish earned balances from injected ones, so you cannot clean up after an incident. ## What the redesign looks like Move the decision, not just the validation. Reduce the API from "set my balance to N" to individually authorizable verbs — "open this chest", "finish this match" — that the server evaluates against its own record of what the player has done. The server owns the economy rules; the client owns the presentation of them. Where full re-derivation is genuinely too expensive, degrade deliberately rather than silently: - enforce invariants (currency is conserved; entitlements only appear via a grant path), - bound rates per account and per action, - detect implausible trajectories and reconcile, - and put the strongest check at the choke point where in-game value converts into something irreversible — a cash-out, a trade, a real-money purchase. ## Where client hardening fits Obfuscation, integrity self-checks and anti-debug measures do have a place: they raise the cost of building the first exploit and slow the packaged tooling that lets thousands of casual users copy it. Model them honestly as **delay**, not prevention — a control that buys time, whose value is realised only if something is watching during that time. They never change who controls the device. An answer that offers client hardening as the primary mitigation is the failure mode interviewers are listening for. ## What you write down A finished model for this design records: the boundary and which side the client sits on; the attacker position (the account holder); the assets (revenue, economy integrity); the threats by category; where each control is enforced; and the residual risk you are consciously accepting, because some fraud always survives and the point of the model is to bound it, not to claim zero.

  • Where do obfuscation and client integrity checks fit in this model, if anywhere?
    As delay controls. They raise the cost of producing the first modified build and slow the spread of packaged cheat tooling, which has real commercial value. But they provide no security property on their own, because the attacker controls the execution environment and can eventually strip them. Model them as buying time, pair them with detection that uses that time, and never let them be the only thing between an attacker and revenue.
  • The server cannot cheaply re-derive every balance from scratch. What do you do instead?
    Degrade deliberately rather than trusting the client. Enforce invariants the economy must satisfy, such as currency being conserved and entitlements only appearing through a grant path. Bound per-account rates for each action. Detect implausible progression and reconcile asynchronously. Then place the strongest synchronous check at the irreversible step — trade, transfer or cash-out — so the expensive verification runs where the loss actually crystallises.
  • Which security property does each dominant threat here violate?
    Tampering with the reported total violates integrity: the value the server stores is not the value its own rules would have produced. Elevation of Privilege violates authorization: the player ends up holding entitlements no legitimate grant path issued. Spoofing, if the client merely asserts an identity rather than proving it, violates authentication. Confidentiality is largely irrelevant here because the data at stake is the player's own.

A restaurant lets guests write their own bill total on a slip. Printing a suggested total on the menu is helpful; it is not the till.

saying these in an interview costs you the question

  • Says the client can be trusted because the build is signed
  • Offers obfuscation as the primary control
  • Treats greyed-out UI or disabled buttons as enforcement
  • Assumes a paying customer would not attack the system
  • Claims a secret header proves the request came from your app
  • Validates the client's total instead of re-deriving it

context