Secure a local file

Compression gzips the save, which changes its size, not its protection. Encryption is the protection, and it offers two modes:

  • Append Hash leaves the save readable, and loads a modified one with a permanent tampered mark.
  • Encrypt makes the save unreadable, and refuses a modified one outright.

The key comes from a secret generated for your project the first time the package runs.

Anchor Save To binds protected data further: to the machine, to its location, or to a runtime secret.

Note: Copying, renaming and deleting a save through the Slots class are not affected by any of this.
Security project settings

The mark Append Hash leaves is readable and settable from code:

// The tamper mark is written into every later save and cannot be edited out
bool cheated = FilePersistenceManager.IsTampered(myData);
FilePersistenceManager.OnTamperedLoaded += target => DisableAchievements();

// When your own checks catch a cheat, brand the save yourself
FilePersistenceManager.MarkTampered(myData);

Secure a remote save

A remote manager protects two copies separately: the one that leaves the device, and the one its cache keeps on the device. Setting Encryption to None and Cache Encryption to Encrypt lets your backend read what it stores while the player's own copy stays opaque.

Not every setting works remotely:

SettingOn a remote manager
Encryption.AppendHashRefused, on the remote save and on the cache alike. The tamper mark is a Local File feature.
SaveAnchor.TargetMachineRefused on the remote save, which has to open on the player's other devices. It works on the cache, where it stops a copied entry opening on another machine.
SaveAnchor.FileLocationBinds to the manager and its slot, so a payload can't move between slots.
SaveAnchor.RuntimeSecretWorks, and keeps the key out of the build.

Fetch a per-player secret at sign-in

A runtime secret keeps the key out of the build entirely. Your game asks your own endpoint for the secret once the player is signed in, then hands it to the package:

// Once per session, before anything loads. A second, different value throws.
CheatProtectionUtility.RuntimeSecret = session.SaveSecret;

The secret must be the same for that player in every session, or their saves stop opening, so derive it from something stable. Until it is set, a manager anchored to it refuses to load and to save: set it before the assets come into scope, or turn Auto Load off and load once you have it.

What it defends against

Neither mode protects from a RAM editor, and a determined reverser can recover the project secret from the build unless RuntimeSecret keeps it out. Treat local protection as cheat deterrence. Competitive integrity needs a server-authoritative design, where the server holds the values that matter.