Sharp Edges GAME DEVELOPMENT NOTES

How to Protect Unity Game Assets From Easy Extraction


You can make Unity game assets harder to extract with off-the-shelf tools, but you cannot make extraction impossible, and the right protection depends on where each asset lives. Unity game assets exist in three places — inside the app package, in separately delivered AssetBundles or Addressables, and in memory once the game has loaded them — and Unity's current documentation offers a point of control in only one of those three.

Unity's own legacy manual stated the limit plainly: if users are determined to extract your assets, they will be able to. The tools are not exotic either. AssetRipper, an open-source tool for analyzing Unity game files, lists support for Unity versions from 3.5.0 to 6000.4.X. The practical goal is narrower than "protect everything": stop easy extraction of the assets that matter, at a cost you can accept.

Where Unity Game Assets Live

Character art, models, and audio take one of three forms on a player's device. Each has a different answer to the question of what you can control.

Where the asset lives Control point in current Unity docs What protection can stop What it costs
Built into the app package (scenes, Resources) None for encryption — —
Separately delivered AssetBundles or Addressables Load bundle data from your own Stream Off-the-shelf tools opening the files directly Stream requirements, memory and loading trade-offs, custom loading code
In memory and on the GPU at runtime None — file encryption no longer applies — —

The decision that matters comes before any choice of cipher. The question is not whether to encrypt, but which of these routes your most valuable assets travel and what that route allows.

Can You Encrypt Assets in a Unity Build?

Not through any option Unity currently documents. Assets referenced by your scenes, and everything placed in a Resources folder, go through Unity's own build pipeline. Unity re-codes imported assets into its own internal formats, and it includes all assets in the Resources folder in a build. Unity's documentation does not describe a step in that pipeline where you can encrypt those assets on the way into the package.

The legacy manual's workaround was to step outside the pipeline. It suggested storing sensitive data as files with a .bytes extension, which Unity treats as a TextAsset, encrypting those files yourself, and decrypting them at runtime. The manual was explicit about what that does and does not cover: with this method the AssetBundles are not encrypted, only the data stored as TextAssets. A texture or model handled that way no longer goes through Unity's normal import and loading path, so your own code takes over the job of turning decrypted bytes back into a usable asset.

For most teams the cheaper move is to take high-value content out of the package rather than to protect it inside the package. That is an editorial judgment rather than anything Unity's documentation prescribes, and it rests on a simple point: an asset that is not in the install cannot be pulled out of the install. Unreleased characters, paid cosmetics, and later chapters are candidates. On Google Play, Play Asset Delivery is one way to keep content out of the first download, covered in how to reduce Unity game size.

How to Encrypt AssetBundles in Unity

Separately delivered AssetBundles are the one place where Unity's current API gives you a documented hook. AssetBundle.LoadFromStream loads a bundle whose data is supplied by a managed Stream object rather than read from a file path. The page itself does not mention encryption; using that Stream to decrypt bundle data as Unity reads it is an inference from what the API allows rather than a use Unity documents.

The hook comes with requirements, and each one shapes what a decrypting stream has to do. All four are stated on the LoadFromStream reference page:

  • Readable and seekable. stream.CanRead and stream.CanSeek must both return true, and the bundle data must start at stream position zero.
  • Thread access. The stream must be accessible from threads other than the main thread, and Unity can call Seek() and Read() from any Unity native thread.
  • Reads past the end. Unity sometimes tries to read past the size of the bundle data, and the stream must handle that without throwing, returning only the bytes actually read.
  • Lifetime. The stream must not be disposed while the bundle or any of its assets is loading; it is disposed after AssetBundle.Unload.

The seek requirement matters most for the choice of cipher. A scheme that can only be decrypted from the beginning, in order, fits poorly with a stream that Unity repositions. The Addressables.CN package states the consequence directly for its own interface: the read stream should support seeking for best performance, and if it does not, a full memory copy of the data must be made.

Compression changes what the stream actually saves. For LoadFromStream, LZMA-compressed data is decompressed to memory, while uncompressed and chunk-compressed bundles are read directly from the stream. Unity also reads through a buffer sized by managedReadBufferSize, and changing it may change loading performance, especially on mobile devices; the reference page suggests trying values between 8KB and 128KB and notes that the best value varies by project and even by bundle.

The common alternative is to decrypt the whole file into memory and load it with AssetBundle.LoadFromMemory. Unity's guide to optimizing AssetBundle memory usage describes how the load APIs handle each compression format and warns that in-memory copies can significantly increase RAM usage and load times. Unity's legacy manual flagged one further cost for bundles fully encrypted at the source and downloaded that way: they won't be cached by Unity's automatic caching. That statement comes from the 5.x-era manual and its WWW download API, so treat it as a reason to test caching in your own setup rather than as a description of current behavior.

Can Addressables Encrypt AssetBundles?

Addressables does not route bundles through a stream you control by default. The default behavior is to use AssetBundle.LoadFromFileAsync when the bundle is in local storage and UnityWebRequest when its path is a URL. Adding decryption means replacing that loading step with a custom provider of your own — an inference from the default behavior, not a documented recipe.

The Addressables.CN package, a separate package from the standard one, does document a hook. Its IDataConverter interface "can be used to provide a custom encryption strategy for asset bundles", with a write stream called by the build process and a read stream called at runtime, and the package also ships stream classes with names such as SeekableAesStream. The standard Addressables package's API reference does not list an equivalent interface. Developers are still asking Unity for built-in options: an October 2026 feature request on Unity Discussions asks for optional encryption of the AssetBundle dictionary as a lightweight deterrent against casual asset rippers, while conceding that a determined reverse engineer could still obtain the key.

That concession is the limit of every client-side scheme. If the game decrypts bundles on the device, the device holds the key and the decryption code at the moment it does so. An extraction tool that can no longer open your bundles shows that the easy path is closed, not that the asset is protected.

Why Unity Runtime Assets Can Still Be Captured

Once a model or texture is loaded, file encryption has already done everything it can. The data has been decrypted, decoded, and handed to the engine and the GPU in the form they need to draw it. Unity's legacy manual named the consequence: there are tools that can record 3D data at the driver level, allowing users to extract models and textures as they are sent to the GPU.

The same split between static files and running processes decides what IL2CPP metadata encryption can achieve, as covered in what IL2CPP metadata encryption can and cannot do. Protection applied to a file on disk raises the cost of reading that file. It does not follow the data into memory, and it does not change what a capture at the graphics driver can see.

None of this makes bundle encryption pointless. It changes who gets your assets easily: anyone with a free tool and a downloaded build, or only someone willing to recover keys from the client or capture frames at runtime.

When Unity Asset Protection Is Worth the Cost

How much protection an asset deserves is a judgment about your own game, not a rule from any documentation. One way to sort assets is by what a leak would actually cost.

Asset What a leak costs A proportionate response
Content already shown in trailers or store pages Little No extra protection
Paid cosmetics and premium content Lost sales if players obtain it without paying Keep it out of the install; deliver it from your server to entitled players; add bundle encryption if casual ripping is a real problem
Unreleased characters, events, and story Spoilers and an early leak Do not ship it in any build before release
Core art that defines the game Clones and reuploads Bundle encryption raises the bar for casual copying; accept that it will not stop a determined copier

The pattern across the table is that delivery decisions do more than encryption decisions. Content that never reaches the device until it is released or paid for is protected by timing and access control, which are simpler to maintain than a custom decryption path.

Unity Asset Protection FAQ

Does encrypting AssetBundles stop tools like AssetRipper?

It can stop such a tool from opening the files directly, which is the easy extraction most leaks rely on. It does not stop someone who recovers the key and decryption code from the client, and it does not apply to assets once they are loaded into memory or sent to the GPU.

Can I encrypt assets that are built into the Unity app package?

Unity's documentation does not describe a way to encrypt scene or Resources content as part of the build. The legacy manual's approach was to store sensitive data as encrypted .bytes files, which Unity treats as TextAssets, and to decrypt them in your own code. Those assets then no longer use Unity's normal import and loading path.

Is it worth encrypting Unity AssetBundles?

For assets whose casual copying would actually cost you, such as signature art or paid content that must ship on the device, it raises the bar at a real cost in custom loading code, memory, and load time. For unreleased or paid content that does not need to be on the device yet, keeping it out of the build entirely protects it more reliably and with less to maintain. For general UI and props already visible in screenshots, it is usually not worth the effort.

Does AssetBundle.LoadFromStream add memory overhead?

It depends on compression. LZMA-compressed bundles are decompressed to memory, while uncompressed and chunk-compressed bundles are read directly from the stream. The read buffer size can affect loading performance, especially on mobile devices, and the best value varies by project.

Sources

← Back to list