"Gold: 9,999,999" — One Text Editor Away From Breaking Your Game Economy
Hundreds of hours of playtesting, a carefully designed in-app purchase model — and none of it matters if an attacker opens a save file on the local device and edits the currency value in a few minutes. If the client trusts data stored on disk without any cross-validation, the entire in-game economy hangs on a single file.
What makes save file tampering especially dangerous is that it requires no advanced hacking skills or specialized tools. A generic text editor or the file browser on a rooted device is often all it takes. The resulting "super accounts" can severely damage multiplayer fairness and eliminate the incentive for legitimate players to make purchases.
This article examines how save files actually get tampered with, why client-side encryption alone doesn't fully solve the problem, and what a multi-layer defense looks like in practice.
Where Save Files Live and What They Look Like
In Unity games, the physical path of saved play data varies by OS platform, but it always ends up somewhere in the device's file system.
- Android: Typically inside
/data/data/<package-name>/files/or on external storage. Access is restricted on standard devices, but freely available on rooted devices and emulators. - iOS: Stored inside the app sandbox, but accessible on jailbroken devices or through third-party backup extraction tools.
- PC (Windows): Saved as files under
%AppData%\LocalLow\<CompanyName>\<GameName>\, or recorded in the registry (PlayerPrefs). Users can access and modify these with no privilege escalation at all.
The format varies — JSON, XML, binary, Unity's built-in PlayerPrefs — depending on how the game is designed. If data is stored as plaintext without encryption or obfuscation, an attacker can understand the structure at a glance and change any value they want.
The Actual Tampering Flow
From an attacker's perspective, manipulating save data follows a simple, intuitive process:
Locate save file ──> Extract and analyze ──> Modify values ──> Overwrite ──> Relaunch game
Step 1: File extraction and structure analysis Extract the target file from a rooted/jailbroken mobile device or a PC. JSON or XML files are immediately readable in any basic text editor. Even binary formats can be reverse-engineered using a hex editor by correlating which bytes change when specific values change — the offset of the target field can usually be pinpointed quickly.
Step 2: Modifying values and flags
Once the structure is understood, the attacker changes "gold": 1200 to "gold": 9999999, inflates character level and stats, and flips the ownership flag of paid items they don't own to true.
Step 3: Overwrite and relaunch The modified file is written back to the original system path and the game is launched. If the client has no integrity check for the file, the tampered values load directly into memory and take effect immediately.
Why Simple Client-Side Encryption Isn't Enough
"Why not just encrypt the save file so it can't be read in a text editor?" This is the natural first question — and client-side encryption does raise the barrier somewhat. But as a standalone measure, it has a critical structural weakness.
The key and logic needed to encrypt and decrypt the file must exist somewhere in the game client's executable. As discussed in the IL2CPP reverse engineering article, attackers can extract decryption functions and hardcoded encryption keys relatively easily via global-metadata.dat dumps or runtime analysis. Once the key is exposed, encryption is just an inconvenient encoding.
And even if encryption holds perfectly, as soon as the client decrypts the data and loads it into memory at runtime, a memory tamper tool can modify the values directly. Simple encryption is a "hard-to-open lock" — it's not a complete verification mechanism that prevents data manipulation.
Effective Save Data Protection Strategies
Protecting player data requires raising the client-side barrier while ensuring that a single point of validation failure doesn't collapse the entire system. A multi-layer (defense-in-depth) approach is needed.
(1) Server-side authority (Source of Truth) Sensitive data — core currency, premium currency, paid item purchase history, multiplayer rankings — should never be trusted based solely on what the client claims. Treat the server's database as the authoritative source, and when discrepancies arise, let the server's values win. Local save files should ideally function as a UI display cache to reduce network latency, nothing more.
(2) HMAC signatures for file integrity verification For games that support offline play and require local saves, attach an HMAC (Hash-based Message Authentication Code) signature to save data using a secret key stored on the server or secured in some way. When the client loads the data, it verifies the signature — any file with even a single modified byte is rejected and flagged as corrupted.
(3) Cloud save (Steam Cloud, etc.) compatible security design A common mistake is generating an encryption key solely from device-specific hardware information (Hardware ID) to prevent unauthorized copying or tampering of local files. This improves security but completely breaks cloud save synchronization for players switching between, say, a desktop and a Steam Deck. Protecting save data while supporting legitimate cross-device sync requires a flexible encryption architecture that ties integrity verification to the user account (e.g., Steam ID) rather than the device.
(4) Pairing file-level protection with runtime memory tamper detection Even if data loads safely through file-level protection (encryption + HMAC), attempts to manipulate runtime values in memory will continue. Core numeric fields must be monitored in real time at the Native layer to additionally suppress memory overwrite attacks that occur after the file loads.
(5) Server-side sanity checks The server should logically validate maximum achievable currency, hourly growth limits, quest reward ranges, and similar thresholds. Any session producing currency far beyond normal ranges should be treated as an anomalous signal and acted upon.
OZero Security provides strong runtime memory value tamper detection and environment integrity verification at the Native C++ layer to prevent manipulated data from affecting gameplay. It also supports a flexible security architecture for safely synchronizing save data across cross-device environments like Steam Cloud without sacrificing file integrity. While physically blocking all local disk access is impossible, precisely detecting when tampered values are loaded into memory and begin affecting logic — combined with server-side verification — enables a robust multi-layer defense.
Summary
- Save files can be easily modified in text-based form in environments with direct file system access (rooted devices, PC) — no advanced hacking required.
- Data encryption is essential, but insufficient as a standalone defense due to the risk of key exposure and runtime memory tampering.
- For primarily offline games, HMAC signatures must strictly block file tampering — and the identification scheme must be account-based to remain compatible with cloud sync.
- Combining disk-level protection with runtime memory detection to cover the secondary manipulation path after file tampering is what makes defense genuinely effective.
A game's save file is a record of the time and effort a player has invested. Designing and verifying it carefully so that trust doesn't become a vulnerability is the foundation of a safe game service.