OZero Security
Documentation

Get Started

This guide walks you through the step-by-step process from installing OZero Security to applying your first security feature. You can complete the basic setup in about 3 minutes even without security expertise.

~ 3 minutes · Unity 2022.3 LTS+ · iOS 14.0+ / Android API 24+

Choose your goal

Start with the path that matches what you need to do now. Each card opens the relevant section of this manual or the API reference.

3-minute quick start Import the package, open the dashboard, apply a preset, and make the first build. Pre-release checklist Review build integrity, platform settings, diagnostics, and Release configuration. Feature configuration Configure the protection modules, common policies, and optional managed UI. Troubleshooting Use support codes, abort codes, and first-check tables for QA or customer support. License and Pro operations Understand activation, Native Variants, telemetry, portal policy, and subscription lifecycle. API reference Look up public types, fields, defaults, enums, callbacks, and error codes.

Overview

OZero Security protects Unity games by executing security logic in the Native C++ layer, which is difficult for general hacking tools to access. Core protection features operate simply by activating modules in the dashboard within the Unity Editor. No scene setup or additional code writing is required.

Built-in protection features:
  • Build integrity check (app tampering detection)
  • Speed hack and time hack detection
  • Memory injection monitoring
  • Encrypted in-game variable types (Secure Types)
  • Encrypted save files and PlayerPrefs
Zero-wiring auto-bootstrap and Config encryption
  • Activated detectors are automatically prepared when the SDK starts. There is no need to place separate objects in the scene or write repetitive initialization code.
  • Security settings are protected during the build process, so plaintext configurations are not exposed in general player distributions.
  • The Native C++ runtime guard provides an additional verification layer outside of managed Unity code.
  • Detection results can be checked through callbacks, logs, and Pro telemetry, making it easy to track causes during testing and operation.

1 Import Package

Open the Unity Editor and import the OZero Security package. You can import it via the Unity Package Manager or by double-clicking the .unitypackage file.

When the Import Unity Package dialog appears, leave all items checked and click Import. The necessary scripts, native plugins, and editor tools will be added automatically.

Import Unity Package dialog with all OZeroSecurity files selected
Before importing, exit Unity Play Mode and, if possible, restart the editor once. If a running player has loaded the OZero DLL, Windows may lock the DLL file, causing the import or overwrite to fail. After importing, Unity will recompile the scripts, so wait until the progress bar in the bottom right disappears before proceeding to the next step.

2 Open Dashboard

Once the import is complete, open the Config Dashboard from the Unity menu bar:

Window -> OZero Security -> Config & Dashboard
OZero Security Config Dashboard opened in the Unity Editor

When the Config Dashboard opens, you can manage presets, security modules, licenses, and build integrity settings all at once on this screen. There is no need to manually locate and modify files in the Project window.

Unity Editor Menu Reference

OZeroSecurity uses Window > OZero Security for setup windows and Tools > OZero Security for diagnostic or bake commands. Security presets are intentionally applied from Config & Dashboard, so you can review the resulting settings before saving.

Menu Role When to use
Window > OZero Security > Config & DashboardOpens or creates the main OZeroSecurityConfig asset.Use this first to apply presets, enable modules, configure response policy, and review build-integrity settings.
Window > OZero Security > License SettingsOpens or creates OZeroLicenseConfig.Use this to enter Standard / Pro license settings, server endpoints, and telemetry options.
Window > OZero Security > Check SetupRuns editor diagnostics for common project and release-configuration issues.Run after import, before a release build, or when a module does not behave as expected.
Tools > OZero Security > Check Integrity ManifestOpens an OZero integrity manifest and displays the decoded content for inspection.Use during build-integrity troubleshooting or support investigation.
Tools > OZero Security > Bake Security Config BlobRegenerates the protected security config blob in StreamingAssets.Use for advanced debugging or CI workflows. Normal player builds bake this automatically.
Tools > OZero Security > Bake Assembly HashRe-bakes oz_ahash.bin for the most recent build output.Use only after a code-only rebuild when the full build pipeline was not re-run.
Tools > OZero Security > Keystore SHA ExtractorExtracts SHA-1 and SHA-256 fingerprints from an Android keystore.Use when filling Android signing fingerprints for Build Integrity checks.
Tools > OZero Security > Add Debug SHA Key to ConfigFinds the Android debug keystore and adds its SHA-256 fingerprint to the config.Use only for local Android debug builds. Release builds should use the release signing key fingerprint.
Tools > OZero Security > Steam Anti-Piracy > Scan Steam RedistributableScans a PC build or plugin folder for Steam redistributable files and known emulator artifacts.Use before Steam release packaging or when checking whether suspicious Steam files are included.
Tools > OZero Security > Check Time.timeScale UsageScans scripts for direct Time.timeScale writes that can conflict with OZero time protection.Run before release or when the Speed & Time Hack module reports a project-side time-scale policy issue.

3 Enable Modules

You can check the list of security modules and toggle switches inside the dashboard. Enable the modules you want to use. Below is the recommended starting configuration.

OZero Security Config Dashboard in the Unity Editor

Select Security Preset

First select a preset, then adjust individual modules to fit your project. For typical live games, we recommend starting with Standard. It offers the best balance of protection level, performance, and false positive risk.

Preset Recommended Use Applied Policy Summary
Low Prototypes, development builds, early QA Maintains only lightweight core checks. Relaxes platform native checks and forced termination policies so test environments aren't blocked too early.
Standard Recommended default for most released games Turns on the core protection set, startup verification, runtime re-verification, emulator checks, and recommended IL2CPP file coverage. A configuration balancing compatibility and protection level.
Strict High-risk live service, PvP, competitive builds Applies the broadest coverage and treats more failures as critical violations. Apply after sufficiently testing platforms, signing, and store distribution flows.
Module Feature Description Recommended
Build Integrity Validator Detect app binary tampering Recommended
Speed Hack Detector Detect time manipulation cheats Recommended
Injection Detector Monitor memory hooking tools Recommended
Install Source Validator Block illegal APKs (Android only) Optional

Simply turn on the modules you want to use in the dashboard and save the OZeroSecurityConfig asset. The SDK will automatically prepare the activated modules when the player starts.

You do not need to place separate objects in the scene. Turn on the desired modules, save the settings, and those modules will initialize automatically from the next run.

License Model — Standard / Pro

Standard provides local protection without server integration. Pro combines project-specific native binaries (Native Variants) and manifest binding with telemetry, signed server time, remote security settings, attestation, and server verification.

The matrix below summarizes from a developer's perspective how the SDK actually behaves at runtime for each tier. For a full feature comparison, check the License Modes Comparison Table on the homepage.
Item Standard Pro
License Key — (None) OZ-PRO-XXXX ×6
Network at boot Not required — fully offline capable One POST /v1/activate per device, then cached
10 Protection Modules All 10 protection modules active All 10 (Same as Standard)
Native Variant Public native module Included
Cloud Telemetry Do not send On — Sends threat events to /v1/telemetry
Signed Time (Clock manipulation prevention) Off — WebTime uses HTTPS HEAD only On — Uses signed /v1/time response
Limit per device Unlimited (No key, no enforcement) Default 5 devices / Adjustable
Source code access Managed C# only Managed C# only
Keep your gameplay code when expanding from Standard to Pro. Apply the dedicated Native Variant package and configure Pro server features in OZeroLicenseConfig.

Registering a Pro License Key

Standard works without separate license setup. For Pro, create the OZeroLicenseConfig asset in Unity and enter the project license key. It binds the dedicated Native Variant and enables runtime activation and server features.

1. Create Config Asset

Open Window → OZero Security → Config & Dashboard. In the License & Server section, click Create OZeroLicenseConfig. The button creates the asset in the correct Resources/ folder, so you do not need to create folders or move the asset manually.

You cannot create this asset directly from the Project window's Create Asset menu. OZeroSecurityConfig and OZeroLicenseConfig do not expose CreateAssetMenu entries to prevent assets from being created in the wrong location. Use the Dashboard button instead.

2. Fill Inspector Fields

Field Required? Description
tier All Tiers Standard uses the shared native module. Pro provides a project-specific native binary, server activation, telemetry, and remote security settings.
licenseKey Pro The project Pro license key in OZ-PRO-... format. It validates the project binding of the dedicated binary and is used for server activation and Pro server features.
allowStandardBuildWithPremiumLicense Pro Explicit native variant compatibility override. Leave it off for normal builds. Enable it only when intentionally building a Pro licensed project with the Standard public native module, or when building Standard with a Pro private native variant package. Standard public variant builds remain keyless even if this option is enabled. Standard + private variant builds must enter the matching license key, and build/runtime validation checks the signed manifest, license key hash, project identity, and native hashes.
appIdentifier Auto sent When Pro activation runs, the SDK sends Unity's Application.identifier value with the request. If this value does not match the Bundle ID or Package Name registered in the customer portal, activation can be rejected. Check the Identifier in Unity Player Settings first.
serverBaseUrl Pro runtime The server address for Pro activation, telemetry, signed time, attestation, and server policies. Serverless mode does not call it. Keep https://api.ozerosecurity.com unless support provides a dedicated endpoint.
serverPublicKeyHex Pro runtime The Pro server signing public key from Customer Portal > Server Key. It verifies server response signatures. Dedicated binary manifests are verified separately with the SDK-embedded binary signing key, not this field.
previousServerPublicKeyHex Pro optional The previous public key used during Pro server signing-key rotation. Enter it only when support asks you to rotate keys; otherwise leave it empty.
tokenTtlSeconds Pro runtime How long a successful Pro activation result can be used while the player is offline. The default 604800 is 7 days. After that time, local protection still runs, but Pro server features such as telemetry and signed time stay off until activation succeeds again.
offlineProPolicyMode Pro A Pro option that decides how local Build Integrity uses signed portal block policies while the device is offline. ApplyCachedBlockPolicies applies only a valid cached policy and is the recommended fail-open default for most live games. RequireFreshPolicy fails closed when no usable signed policy is available and server Integrity is enabled. IgnoreCachedBlockPolicies bypasses the cached policy for tests or migrations. See OZeroOfflineProPolicyMode for each value.
activationTimeoutSeconds Pro runtime How many seconds the SDK waits for the Pro activation request, /v1/activate. The default is 6.0. If the server does not answer in time, the SDK does not block scene loading. It uses a valid Pro cache when available; without a cache, only the selected server features stay unavailable while local protection continues.
enableLog Optional When enabled, license-flow events such as cache use, activation success, timeout, and signature mismatch are written through OZeroSecLog. Keep it on during integration because it makes setup issues easier to find. Turn it off for release builds if you want fewer logs.
Pro server features
enableDevicePolicyHeartbeat Pro Periodically asks the Pro server whether the current device has been blocked in the customer portal. If the server returns DEVICE_BLOCKED, the SDK clears cached Pro entitlement data and blocks the app.
devicePolicyHeartbeatInterval Pro The base interval for checking whether the device is blocked. Default is 300 seconds. Set it to 0 to disable periodic checks.
devicePolicyHeartbeatJitterPercent Pro A percentage that slightly spreads out the check timing so many devices do not call the server at the same moment. The default 20 means the SDK shifts the timing a little around the configured interval. Valid range: 0 to 75.
enableSecurityLevelCheck Pro When enabled, the app asks /v1/security-level to confirm this build's security settings at startup. The server can reject the build if it is below the minimum level required in the portal. Default is false.
declaredSecurityLevel Pro The security level this build reports to the server. Default is Standard. Use Low for prototypes or internal tests. Use Strict only after QA has confirmed the stronger policy does not block normal users.
failOnSecurityLevelReject Pro When enabled, the app follows the block flow if the server clearly rejects the security level or config hash. Simple network errors, server maintenance, or license maintenance states are not treated as tampering; they only disable Pro server features.
securityLevelCheckInterval Pro How often the app checks the security level again while it is running. Default 0 means the check runs only once at startup.
securityLevelCheckJitterPercent Pro A percentage that slightly spreads out repeated security-level checks so many devices do not call the server at the same moment. Default is 20. Valid range: 0 to 75.

3. Build & Verify

You do not need to add extra code. When the app starts, the SDK automatically reads the OZeroLicenseConfig asset. On the first run, check the Player log for a line such as [OZeroLicense] activated; tier=pro caps=5. If you configured Pro but the log says Standard mode, check the asset location and name first. The asset must be under a Resources/ folder and must be named exactly OZeroLicenseConfig.

The license key cannot be hidden at runtime like a password because it is included with the build. Still, do not post it in public repositories, documentation, or screenshots. If exposed, someone else can consume your device allowance. Treat it like a product code.

Offline Behavior

The short version: losing the network does not stop the game or local protection. Standard does not use the server at all. Pro keeps the same offline local protection, while explicitly selected server features can use saved activation information for a limited time.

Standard — starts without internet

Standard does not ask any server for permission. It runs the local protection modules bundled in the app, so the game starts even when the player is offline. Only Pro server features such as telemetry and signed time are unavailable.

Pro — local protection stays offline; selected server features use cache

When optional Pro server features are enabled, the device and license are confirmed while online. Selected server features can tolerate a temporary disconnection for a limited time. This check does not gate builds made with an acquired Native Variant or local protection.

tokenTtlSeconds is the lifetime of that saved server-feature result. The default is 604800 seconds, or 7 days. After it expires offline, only server-dependent features such as telemetry upload and signed-time verification stay unavailable until the next successful activation. The game, acquired Native Variant, and local detectors continue unchanged; the SDK does not silently switch the product tier to Standard.

Pro — portal-blocked builds stay blocked offline

A temporary server or network problem is different from a build that an operator intentionally blocked in the portal. When Pro activation succeeds, the server also sends a signed block list, such as blocked build hashes, SDK versions, and app versions. The SDK keeps this policy separate from the temporary server-feature state.

Configure this behavior in OZeroLicenseConfig.offlineProPolicyMode from the License & Server section of the Config Dashboard. The option controls how local Build Integrity handles the last signed Pro portal block policy when the device cannot reach the server.

Mode When to use
ApplyCachedBlockPolicies Recommended default for most live games. If a valid signed policy cache exists, builds or versions blocked in the portal remain blocked offline. If the cache is missing, deleted, or expired while the device is offline, this policy gate passes instead of failing the build.
RequireFreshPolicy Strict mode for online-centered games. If no usable signed policy is available, such as first launch, reinstall, cache deletion, or cache expiry, Build Integrity fails instead of trusting old or missing policy data. This fail-closed behavior requires server Integrity to be enabled.
IgnoreCachedBlockPolicies Bypass mode for tests or migrations. The SDK does not read cached portal block policies while offline, so portal block rules are not applied by this gate. Not recommended for live service builds.

In short, ApplyCachedBlockPolicies is a fail-open operating default, RequireFreshPolicy is a fail-closed policy mode, and IgnoreCachedBlockPolicies is a test bypass. If every validation must require online server confirmation, also configure the server Integrity or Managed Verification requirements instead of relying on this option alone.

With ApplyCachedBlockPolicies, the SDK cannot apply portal block policies during a fully offline first launch, reinstall, cache deletion, or cache-expired start. Use RequireFreshPolicy together with server Integrity when those cases must require a valid signed policy.
State Detectors Telemetry Signed Time
Online, Just Activated All 10 On On On
Offline, saved Pro info still valid All 10 On Off (offline events are not stored) Uses WebTime fallback when possible
Offline, saved Pro info expired All 10 On Off (until next online activation) Off (until next online activation)
First launch + fully offline All 10 On Off until first online run Off until first online run
Telemetry is sent only while the device is online. If an event happens offline, the SDK records one warning log and discards that event instead of saving it to disk. This avoids leaving a local queue that attackers could edit. When the device is online again, new detection events are sent normally.

License Issues

If something looks wrong, first search the Unity Player log for [OZeroLicense]. This tells you whether the SDK started as Standard, whether Pro activation succeeded, and why it downgraded to Standard when activation failed. For security-event upload issues, also search for [OZeroTelemetry].

What you see in the log Meaning What to do
[OZeroLicense] Standard / serverless mode. The SDK started in Standard mode. This is normal if you meant to use Standard. If you expected Pro, confirm that OZeroLicenseConfig.asset was created from Window → OZero Security → Config & Dashboard and is under Resources/. The asset name must be exactly OZeroLicenseConfig, and tier=Pro plus licenseKey must be filled.
Pro->Standard downgrade: /v1/activate returned LICENSE_NOT_FOUND The server could not find this license key, or the key is not usable right now. Compare licenseKey with the key shown in the Customer Portal. Keep casing and dashes exactly as shown. If the portal status is pending, suspended, revoked, or expired, Pro activation will not succeed.
ANDROID_BUNDLE_ID_MISMATCH / WINDOWS_PRODUCT_NAME_MISMATCH The app identity in this build does not match the value registered in the portal. For Android/iOS, check Application.identifier in Player Settings. For Windows, check Company/Product names. For WebGL, check the runtime origin. If these do not match the portal record, /v1/activate is rejected. After changing the value, test with a fresh build.
activation token signature verification failed The server responded, but the SDK decided it could not trust that response. This applies only to Pro activation. Copy the Active publicKey from Customer Portal > Server Key into OZeroLicenseConfig.serverPublicKeyHex. Paste only the 64-character hex publicKey, not the kid prefix. If the exact value still fails, test once on a direct network outside corporate proxy/MITM equipment.
private native variant manifest signature is invalid The Variant package manifest is missing, edited, or was not signed by the trusted OZero Variant signing key. Do not fix this by filling serverPublicKeyHex. For Pro Variant packages, re-download the assigned Variant package and keep the manifest and native plugin files from the same package. If the newly downloaded package still fails, send the manifest file and Unity build log to OZero support.
DEVICE_BLOCKED This device is blocked in the Customer Portal. Review the security events for that deviceId in the portal. Keep the block if it was a real attack or policy violation. If it was a QA device or a false positive, unblock it in the portal. The SDK clears stored Pro entitlement and runs the block flow when it receives this response.
ACTIVATION_LIMIT This license has no room for another newly activated device. Remove old test devices in the portal. If this is caused by real users, raise the device limit for the license.
/v1/activate timed out / network error The device could not reach the server, or the response was too slow. Check whether the device can reach https://api.ozerosecurity.com/health. Also check firewall, proxy, DNS, and captive-network conditions. In high-latency regions, try increasing activationTimeoutSeconds. If saved Pro info exists, the SDK uses it first.
cached entitlement past TTL; clearing. The saved Pro information is past its trust window. If the device stays offline longer than tokenTtlSeconds, saved Pro info is no longer trusted. The game keeps running at Standard level, and Pro features return after the next successful online activation. If long offline play is common, increase TTL.
SERVER_NOT_CONFIGURED / SIGN_FAILED The server could not sign the activation token. This is usually a server Server Key or encryption-key state issue, not a client-side typo. Check the Customer Portal Server Key status. On production, send the log time, partial licenseKey, and platform to OZero support.
We recommend turning off enableLog in release builds. Logs are useful for QA, but general user builds do not need to expose tier, feature state, or detection-flow details.

Project Settings

Before adjusting individual security modules, first check the Unity Player Settings that affect native plugins, store builds, and platform verification.

Minimum Build Targets

Platform Minimum Target Description
Unity Editor 2022.3 LTS+ OZero Security SDK 1.0.5 requires Unity 2022.3 LTS or later; Unity 6 is verified as well. Older 2021.3 projects must upgrade before importing the package.
iOS 14.0+ For iOS builds, set Project Settings > Player > iOS > Target minimum iOS Version to 14.0 or higher. The ABI 21 injection detector uses the iOS 14 shared-cache API to tell Apple system images from injected code, and the Editor preflight fails for a lower target.
Android API 24+ For Android builds, set Project Settings > Player > Android > Minimum API Level to Android 7.0 Nougat (API level 24) or higher. Store release builds are recommended to use IL2CPP and ARM64.
Apple privacy manifest: The SDK includes PrivacyInfo.xcprivacy. The Unity post-processor adds it to the iOS Xcode app target and to Contents/Resources for macOS. The manifest declares the UserDefaults CA92.1 reason because OZero uses Unity PlayerPrefs for app-local SDK state. Keep the manifest in the final app and review the Xcode privacy report before submission.

Recommended security and size settings for release builds

When you publish the final release build, OZero recommends the following Unity settings to strengthen the build and reduce app size.

Security hardening (IL2CPP): On Android, iOS, and other Unity-supported targets, set the scripting backend to IL2CPP. IL2CPP does not make reverse engineering impossible, but it reduces direct C# metadata exposure and helps OZero security checks run on a stronger release baseline. Path: Project Settings > Player > Other Settings > Scripting Backend

Size optimization (Managed Stripping): Managed Stripping removes unused managed code to reduce app size. If too much code is stripped at once, the app may fail at runtime, so start with Low or Medium.

Important: After changing these settings, test scene transitions, save/load behavior, Addressables, and external SDKs such as payments or ads on a real device before increasing the stripping level.

PCs running Windows Standalone builds must have the Microsoft Visual C++ Redistributable 2015-2022 (x64) installed. If this runtime is missing, Windows may fail to load the OZero native plugin, and the app may close shortly after launch. When distributing via Steam, a launcher, or a standalone installer, configure the VC++ Redistributable to be installed together as a prerequisite.

Android ProGuard / R8 Settings

OZero Security does not require a separate Java SDK package. However, if Minify, ProGuard, or R8 is enabled in an Android release build, you must preserve the Unity Java bridge and custom Android bridge classes used in your project. This ensures that JNI calls required for package information, install source, APK signature certificate checking, and boot asset loading operate stably even after obfuscation.

In Unity, open Project Settings > Player > Android > Publishing Settings. If you turned on Minify Release, enable Custom ProGuard File as well and add the rules below to proguard-user.txt. If you do not use Minify, no separate ProGuard setup is required.
# OZero Security - Unity Android ProGuard/R8 keep rules
-keep class com.unity3d.player.UnityPlayer { *; }
-keep class com.unity3d.player.UnityPlayerActivity { *; }
-keep class com.unity3d.player.UnityPlayerGameActivity { *; }
-keep class com.unity3d.player.UnityPlayerForActivityOrService { *; }
-keepattributes *Annotation*,InnerClasses,EnclosingMethod,Signature

# If your game adds custom Java/Kotlin bridge classes that OZero or your code
# calls through AndroidJavaClass / AndroidJavaObject, keep those classes too.
# Replace the package below with your own bridge package.
# -keep class com.yourcompany.yourgame.bridge.** { *; }

5 OZeroSecurityConfig Settings

The OZeroSecurityConfig ScriptableObject asset is included when the package is imported. Select it in the Project window to review and adjust all security module settings. It can be accessed at runtime via OZeroSecurityConfig.Instance.

OZeroSecurityConfig Inspector panel in the Unity Editor

Common Settings

Top-level settings shared by all security modules. Defaults in this table use the serialized values defined in code.

Field Type Default Description
developerSecret string "" Project-specific secret used to protect OZeroSV_File and OZeroSafePlayerPrefs data. Generate it with Generate Secure Secret in the Config Dashboard instead of typing a random string by hand. Use a different value per game, keep it out of documents, logs, and public repositories, and do not change it after release. If this value changes after release, protected data saved by older builds cannot be decrypted by newer builds.
enableLog bool false Turning on Enable Debug Logs prints internal states such as SDK initialization, settings loading, license/telemetry flow, and detection events to the Unity Console and Player log. It is useful for identifying causes during development/QA stages, but we recommend turning it off in production builds as detection flows and module states may be exposed.
enableFailureDiagnostics bool false Turning on Enable Failure Diagnostics saves a local diagnostic file to Application.persistentDataPath when a security violation occurs. Since the file may contain module names, hashes, device state, installation package names, and some runtime settings, it is recommended to turn it on only during QA or customer support sessions.

Default save locations by platform:
  • Windows: %USERPROFILE%\AppData\LocalLow\CompanyName\ProductName
  • macOS: ~/Library/Application Support/CompanyName/ProductName
  • Linux: ~/.config/unity3d/CompanyName/ProductName
  • Android: /storage/emulated/0/Android/data/package.name/files
  • iOS: Documents folder in the app sandbox
  • WebGL: Browser IndexedDB-based /idbfs storage
Important: before the first release, click Generate Secure Secret and save the generated developerSecret. Do not change it after launch. If this value changes, existing OZeroSV_File and OZeroSafePlayerPrefs data cannot be decrypted by newer builds.

Managed UI (All licenses)

Security Termination Notice, the shared dialog prefab, and localization are available in Standard / Pro. Pro additionally exposes Managed Verification retry, timeout, and provider settings. Before importing the optional package, use Package Manager to install Unity UI and TextMeshPro. The notice describes an already-armed fatal response; it cannot cancel exit or extend the native deadline.

Build preflight: the optional TMP package is required whenever Security Termination Notice uses OZeroBuiltIn on any license, or Pro Managed Verification uses a built-in dialog. Missing prerequisites stop the build. Dedicated Server cannot use Built-In UI; select Disabled or custom callback/logging. Use Window > OZero Security > Check Setup and Import Package for graphical projects.
Localization: OZero supplies EN, KO, JA, ZH-CN, and ZH-TW safe text. Selection follows securityUiLanguageCode, configured fallback, then English. Managed Verification server Reason is never rendered raw. Use Tools > OZero Security > Localization > OZero Security UI Text for extensions.
Fail-close boundary: Bootstrap/config/trust/initial variant or assembly validation and watchdog-start failures exit immediately without a popup. Boot-ACK timeout, watchdog termination, actual crashes, OS kills, and headless execution also do not guarantee UI. Notice dispatch applies only after RuntimeNoticeReady. Show only the safe OZ-SEC-* code, never raw internal detection data.
Native release contract: Windows, macOS, Linux, Android, and iOS players require a matching ABI 18 native variant, a valid OZero-signed Variant Manifest V3, and an exact 8-byte oz_boot.bin whose bootstrap policy fields match the protected configuration. A missing, malformed, unsigned, mismatched, or ABI 17 artifact is a build/runtime failure. oz_boot.bin contains only plaintext environment flags; it is not a tamper-authentication artifact.
Font scope: the optional package embeds Static TMP SDF subsets only for OZero's supplied EN, KO, JA, ZH-CN, and ZH-TW dialog strings. The supplied strings need no extra font work. If you change text, add a locale, or display characters outside that set, regenerate the Static SDF from the charset files or use fonts referenced by a project-owned custom prefab. Otherwise missing glyphs may appear. Keep customized prefabs and fonts in a project-owned folder instead of editing the OZero originals.
Field Type Default Description
securityTerminationNoticePolicyenumDisabledAll licenses. Chooses no notice, OZero Built-In UI, or a custom callback for runtime fatal events. Low and Standard security presets select Built-In; Strict selects Disabled. Initial fail-close paths never show this notice.
securityUiDialogPrefabResourcePathstring""All licenses. Optional Resources path for a project-owned security dialog prefab. Empty uses the optional TMP package default. The former managedVerificationDialogPrefabResourcePath value migrates automatically.
securityUiLanguageCodestringautoAll licenses. Language for termination and managed-verification UI. auto follows Application.systemLanguage. The former managedVerificationLanguageCode value migrates automatically.
securityUiFallbackLanguageCodestringenAll licenses. Fallback language before the built-in English safe text. The former managedVerificationFallbackLanguageCode value migrates automatically.
managedVerificationUiPolicy (Pro)enumBuiltInBlockingDialogPro only. Chooses the user-facing flow for OZero Managed Build Integrity and Steam DRM states. Built-in blocking/non-blocking dialogs require TextMeshPro and the optional OZeroSecurity_BuiltInDialog_TMP.unitypackage. Use Custom UI / Callback Only when your game replaces that UI through RegisterUserManagedVerificationStateCallback or when the project does not import the TMP dialog package.
managedVerificationRetryTimeoutSeconds (Pro)int15Maximum time to wait after the user presses Retry before moving to a retry-timeout state. Use this to avoid leaving the player in an indefinite verification wait.
managedVerificationOnlineRequiredTimeoutSeconds (Pro)int120Maximum time to keep the online-required dialog waiting before the configured timeout action is applied.
managedVerificationTimeoutAction (Pro)enumBlockSessionControls what happens when verification does not recover in time: keep showing the dialog, block the protected session, abort the app, or only invoke callbacks for a custom flow.
autoRetryManagedVerificationWhenNetworkRestored (Pro)boolfalseAutomatically retries managed verification after network connectivity returns. Enable only when your game can safely retry without an explicit player action.

Global Threat Response

Determine how the game will respond when a security threat is confirmed. During testing, check callbacks and logs first, and in actual deployment builds, choose the notification time for players and the termination policy according to your project's operation method.

Field Type Default Description
forceQuitOnDetection bool true forceQuitOnDetection determines whether the SDK will automatically exit the game when a confirmed threat is detected. Turning it off is convenient for QA as you can only check callbacks and logs, but in an actual deployment build, a bypassed client may continue to run, so choose carefully.
fatalCallbackGraceSeconds float 10 fatalCallbackGraceSeconds is the maximum time allowed for the game's security callback to show a player notification UI after a threat is detected. The default value is 10 seconds. If set to 0, it will behave as before, terminating immediately without any notification time.

Integration Troubleshooting

If the app closes after enabling OZero Security, or only fails in a specific environment, first use the local diagnostic file to identify which module reacted. Instead of guessing, follow the tables below using the module, subCode, and reason values from the file.

If a termination notice displays an OZ-SEC-* support code, include it in the support request. No popup does not prove OZero was uninvolved: startup fail-close, Boot-ACK/watchdog termination, crashes, and OS kills may exit before UI. Check ozero_abort.txt, the Player log, Check Setup, and build preflight results. Strict preset intentionally defaults the notice to Disabled.
Turn on Enable Failure Diagnostics only while investigating a QA or customer-support issue. The file can include module names, hashes, device state, installer package names, and runtime settings. Do not ship public release builds with this option left on.

When the app keeps closing

Step What to do How to read it
1Open Window > OZero Security > Config Dashboard in Unity, then turn on Key Common Settings > Enable Failure Diagnostics in OZeroSecurityConfig.Use this only while investigating a QA or support issue, and do not ship public release builds with it enabled.
2Before changing more settings, reproduce the issue once with the same build.If you change several settings before reproducing, it becomes harder to identify the cause. Capture the diagnostic file for the current state first.
3Open the latest ozero_*_failure.log file under Application.persistentDataPath.Build Integrity may also create ozero_integrity_failure.log plus a more specific file such as ozero_integrity_platform_native_failure.log. If the app exits very early and no failure log exists, also check ozero_abort.txt and the Player log.
4After collecting the file, turn Enable Failure Diagnostics off again.Do not leave local diagnostic files enabled in public release builds unless your support process explicitly requires it.

Fields you will usually see

Field Meaning What to check next
moduleThe protection area that produced the event.Start with the matching FAQ row, then open the related manual section such as Build Integrity, Speed & Time Hack, Injection, Install Source, or License.
subCode / checkNameA shorter reason code or check name.Use it to choose the matching symptom family below. For example, platform_native means you should first check platform, emulator, signing, root, or jailbreak settings.
reason / subReasonA human-readable summary of why the SDK reacted.Treat this as a hint, not the final answer. Check module and subCode first, then find the row below that uses the same keyword.
platform / buildTypeWhere the app was running and whether it was an editor, development, or release build.Separate QA-only emulator or development-build issues from real release-device issues.

Common symptoms and first checks

Symptom Likely area First thing to try
The app closes right after applying OZero.A security response may have fired during startup.Enable Failure Diagnostics, reproduce once, then read module, subCode, and reason. If there is no failure log, check ozero_abort.txt and the Player log. Also run Window > OZero Security > Check Setup in Unity.
The app keeps closing on an Android emulator.Build Integrity or platform native checks may be treating the emulator as an unsupported runtime.For emulator QA, relax blockEmulator (Android) or the related platform check policy. Re-enable the release policy before store builds if your game should block emulator environments.
License activation fails or an optional Pro server feature is unavailable.License key, app identity, network, or server signing key.Open License Issues and check the exact log line, such as LICENSE_NOT_FOUND, ANDROID_BUNDLE_ID_MISMATCH, timeout, or signature verification failure.
Build Integrity or manifest validation fails.Missing, old, unsigned, or mismatched manifest data.Run Check Setup, regenerate the integrity manifest, validate signing keys, and make a clean build. Do this after code, IL2CPP output, watched files, or the manifest signing key changes.
The app closes after pause, slow motion, or fast-forward.Direct Time.timeScale writes can look like time manipulation.Use OZeroTime.timeScale. Keep TimeScaleTamperExemptions only for verified plugins or legacy adapter scripts.
The app closes during a long loading screen.The main thread stayed blocked for a very long time (the Watchdog tolerates blocked threads, but closes a process that stays stalled for more than five minutes).Wrap trusted long loading boundaries with OZeroWatchdog.BeginLoadingGrace. Do not use it to hide normal gameplay stalls.
Android works before Minify/ProGuard/R8, but closes after enabling it.Unity or custom Android bridge classes may have been stripped or renamed.Apply the Android ProGuard / R8 keep rules, especially for Unity bridge classes and any custom Java/Kotlin bridge your project calls.
Windows Standalone closes immediately on a clean PC.The OZero native plugin or VC++ runtime may not load.Install Microsoft Visual C++ Redistributable 2015-2022 (x64) and confirm the OZero native plugin is included in the build output.
A normal overlay or recording tool triggers an Injection event.Injection/Hooking is observing a loaded module.First check the detected module name, hash, and signer from Failure Diagnostics or the Pro portal. If the module is a normal program, Pro customers press Allow on the row in the portal (Injection → Observed modules); the decision reaches every device with the next list refresh. Standard customers add the hash to injectionWhitelistEntries and ship a new build. Never allow a module you cannot name.
The build stops because the optional Built-In TMP Dialog package is not ready.A built-in Managed Verification UI policy is selected, but TextMeshPro, TMP Essential Resources, the OZero dialog component, or its default prefab is missing.Open Window > OZero Security > Check Setup and click Import Package on the Built-In TMP dialog error. Wait for package import and script compilation, run Check Setup again, then rebuild. If the game supplies its own UI, select Custom UI / Callback Only.
Release reminder: Before shipping, review any settings you relaxed during troubleshooting. Emulator blocking, force-quit policy, manifest signing, ProGuard rules, and local diagnostics should be restored or intentionally confirmed for the release policy.

Build Integrity Validator Settings

Configure the build integrity checker to detect modified game files, debugger attachments, and abnormal execution environments.

Field Type Default Description
Activate Build Integrity checkbox On Dashboard checkbox that activates the Build Integrity module. Internally it maps to useIntegrity.
validateOnStartupbooltrueExecute the build integrity check immediately upon game execution.
validateInEditorboolfalseExecute validation even in the Unity Editor (useful for testing, but recommended to turn off during general development).
enablePeriodicValidationbooltrueRepeats integrity validation even while the game is running. It is recommended to keep this on unless a single validation at startup is sufficient for your build.
periodicCheckIntervalfloat300 sBase interval in seconds for repeating Build Integrity validation while the game is running. Set to 0 or less to disable periodic checks.
periodicCheckJitterPercentfloat35%Adds random variation to the validation interval, making check timing harder to predict. Exact intervals and ranges are not disclosed publicly; using the default value is recommended.
timingAnomalyConsecutiveRequiredint7Determines how many timing-based anomaly signals must accumulate before being judged as debugger timing drift. Strong debugger signals may still fail immediately.
timingAnomalyWindowSecondsfloat900 sTime window for accumulating timing-based anomaly signals. Longer is more lenient; Strict uses a shorter window.
timingAnomalyFrameHitchSuppressionSecondsfloat20 sRelaxes timing-based debugger checks for a certain period after a large frame hitch, such as scene loading, shader compilation, GC, or OS scheduling delays.
checkAssemblyHashbooltrueVerifies compiled assembly hashes against the manifest generated at build time.
checkDebuggerbooltrueDetects debugger attachment and debugger-like runtime timing behavior.
failOnDebugBuildboolfalseConsider Unity debug builds as a violation (recommended for release builds).
checkPlatformNativebooltrueRuns platform-native checks. Depending on platform, this may include root or jailbreak state, APK signing, runtime environment, proxy, or analysis-tool signals.
failIfManifestMissingboolfalse*Inspector default is off for development convenience. In non-development player builds it is forced on, so a missing or unreadable oz_manifest.ozero is treated as a violation.
failIfAssemblyHashBlobMissingboolfalse*Inspector default is off for development convenience. In non-development player builds it is forced on, so deleting the generated assembly-hash blob cannot silently bypass hash verification.
requireCodeSignature (Windows)boolfalseThe main executable file must be code-signed. Windows only.
blockVirtualMachine (Windows)boolfalseBlock game execution inside a virtual machine. Windows only.
blockHyperV (Windows)boolfalseBlocks Hyper-V VMBus signals. Users of WSL2, Docker Desktop, and Windows Sandbox may also be blocked, so use cautiously only in controlled environments.
blockNetworkProxies (Windows)boolfalseDetects execution signals suspected of being network proxies, packet inspection, or traffic analysis tools. Use in competitive builds, but test for false positives first.
blockReverseEngineeringTools (Windows)boolfalseDetects execution signals suspected of being reverse engineering or debugging tools. Verify separately for development/QA environments and live environments.
blockSystemMonitorTools (Windows)boolfalseDetects execution signals suspected of being process/system monitoring tools. Consider the possibility of false positives in normal user environments.
il2cppHashGameAssemblybooltrueHash verifies GameAssembly.dll for Windows IL2CPP builds. This is the minimum recommended coverage for IL2CPP file protection.
il2cppHashGlobalGameManagersboolfalseAdds globalgamemanagers to Windows IL2CPP file hashing. The code default is off, but the Standard and Strict presets turn it on.
il2cppHashSharedAssetsboolfalseAdds sharedassets* files to Windows IL2CPP file hashing. The code default is off, but the Standard and Strict presets turn it on.
il2cppHashSceneFilesboolfalseAdds Unity scene files such as level* to Windows IL2CPP file hashing. The code default is off, but the Standard and Strict presets turn it on.
il2cppHashResourcesAssetsboolfalseAdds resources.assets to the IL2CPP verification scope. Useful for Strict mode, but test your patch flow first.
il2cppAdditionalWatchedFilesList<string>If the project includes separate native payloads, specify additional Windows IL2CPP output files to monitor.
blockEmulator (Android)booltrueAndroid only. Treat emulator or unsupported runtime signals as integrity violations. Relax during QA/emulator testing and recommend a stricter policy for production builds.
blockSystemRwMount (Android)booltrueAndroid only. Treats writable system partitions or root-like mount states as integrity violations. The Standard preset relaxes this to reduce false positives on unlocked or rooted QA devices.
linuxHostLayerPolicy (Linux)enumMonitorHow the SDK reacts when a Linux host layer such as LD_PRELOAD, LD_AUDIT or WINEDLLOVERRIDES sits between the game and the OS. Off ignores it, Monitor (default in every preset, Strict included) records it without closing the game, Block treats it as a violation. Normal Steam Linux and Proton players use these layers, so Block is only for games that have verified their player base.
protonPolicy (Linux / Proton)enumMonitorSame three values for a Windows build that is running under Proton or Wine. The default Monitor keeps Steam Deck and Proton players playable while still recording the environment in telemetry.
acknowledgeHostLayerBlockboolfalseMust be switched on before a Block host-layer or Proton policy is accepted. The build preflight fails when Block is configured without this acknowledgement, so nobody ships a build that closes the game for legitimate Linux players by accident.
nativeModuleInventoryPolicyOff | Monitor | BlockBlock (Low: Monitor)Windows and Linux players only. The build records every native module (*.dll / *.so) below the game folder in the signed integrity manifest. At start-up Build Integrity lists the folder and hashes the recorded files: a native file that is not in the list, or whose hash changed, is a violation. Block (default) terminates, Monitor logs and continues, Off skips the check. The Injection detector uses the same list to recognise the game's own plugins. Choose Monitor if your players are allowed to add native mod loaders to the game folder. The Low preset uses Monitor.
androidShaKeysList<string>List of expected APK signing certificate SHA-256 fingerprints. If the installed APK is not signed with one of these keys, the verification fails (Android only).
expectedBundleIds (iOS)List<string>List of allowed iOS Bundle IDs. If left empty, the Bundle ID check is skipped.
excludedAssembliesList<string>List of assembly names to exclude from hash verification (excluding the .dll extension). Use for assemblies that change at runtime (e.g., generated code).
checkIntegrityWithServer (Pro)boolfalseEnables the Pro nonce → attest flow. After local Build Integrity passes, the SDK submits build integrity evidence to OZero. With attestationVerificationMode=OZeroManaged, the optional OZero TMP dialog package, and a built-in Managed Verification UI, no game code is needed for the user-facing verification flow.
attestationVerificationMode (Pro)enumCustomerGameServerChoose who makes the final verdict for the OZA token. OZeroManaged lets the SDK ask OZero for a managed client-session verdict. In CustomerGameServer, your backend issues the binding and the client calls RequestGameServerAttestation(audience, challenge, sessionId) before your backend validates the OZA token through OZero APIs.
attestationNetworkPolicy (Pro)enumRequireOnlineRevalidationServer verification that cannot be completed or refreshed surfaces an online-required state. With OZeroManaged and the built-in UI, retry, timeout, and blocked states are shown through the SDK dialog automatically.
manifestSigningPublicKeystring""Base64 RSA-2048 public key used to verify the signed Build Integrity manifest. Generate it from Window > OZero Security > Config & Dashboard with Generate Key Pair. This is separate from the customer-portal server key used by OZeroLicenseConfig.
requireManifestSignatureboolfalse*Inspector default is off before keys are generated. In release player builds, manifest signature verification is forced on, so generate a key pair before release.
manifestSigningPrivateKeyPathstring""Private key PEM path used for manifest signing during the build. If left empty, OZero uses [ProjectRoot]/OZeroSigningKeys/manifest_private_key.pem. This is Editor-only and not included in player builds.

OZero server attestation with the default UI

For the no-code flow, enable checkIntegrityWithServer, set attestationVerificationMode to OZeroManaged, import the optional OZero TMP dialog package, and keep the Managed Verification UI policy in General Settings on a built-in dialog. The SDK obtains the nonce, submits attest evidence, asks OZero for a managed session verdict, and shows network-required, retry, timeout, warning, or blocked states through the default dialog. Register RegisterUserManagedVerificationStateCallback when replacing the default UI, avoiding TextMeshPro, or adding your own telemetry/session gate.

💡 Tip: Protect live builds with a stronger policy

Pro Strict Attestation is a stronger mode that can be enabled from the Pro policy in the customer portal. In this mode, the OZero server does not issue an OZA token immediately; it first checks whether the request comes from an active build registered in the portal. It also verifies that the submitted nonce, manifest hash, platform, SDK version, and app identity belong to the same request flow. Debugger, platform, speedhack, and injection checks must be clean, and at least one assembly/file/IL2CPP hash must be verified. If the conditions are not met, no OZA token is issued, so register the build version and manifest hash in the customer portal before releasing a new build.

Events

Event Description
OnValidationPassed Fires when the local integrity check completes without violation. Pro server attestation may still be in progress.
OnAttestationPassed Fires only after the Pro OZA attestation token is actually issued. Use this event or AttestationToken.IsValid(nowMillis) to check and proceed with game server logins, PvP, rankings, and currency flows.
OnValidationFailed Fires when the integrity check detects a violation. The global onHackDetected event is also triggered along with ModulationType.BuildIntegrity.

Generate RSA Signing Keys (Build Integrity Manifest)

Build Integrity can add an RSA signature to the manifest generated at build time. The manifest contains the assembly hashes and file integrity information that the SDK will verify at runtime. In release builds, the SDK must also know that this manifest itself has not been replaced, so create the manifest signing key pair from Window > OZero Security > Config & Dashboard before shipping.

Why manifest signing matters

At build time, OZero signs the manifest with the private key. The private key is not included in the player build; only the public key stored in OZeroSecurityConfig is included. At runtime, the SDK uses that public key to check whether the manifest is still the one created during the build. If the signature is valid, the SDK uses that manifest as the trusted baseline for assembly and file hash checks. If the signature is missing or does not match, the manifest may have been replaced or edited, so Build Integrity treats it as a failure and follows your Response Settings.

Build Integrity Manifest Signing UI in the Unity Editor

Generate a key pair

  1. In the Unity Editor, open Window > OZero Security > Config & Dashboard.
  2. Expand the Build Integrity section in the Inspector.
  3. Enable the Require Manifest Signature checkbox.
  4. Click the Generate Key Pair button.
  5. OZero generates a key pair for Build Integrity manifest signing. The public key is stored in OZeroSecurityConfig, and the private key is saved to this default path:
    [ProjectRoot]/OZeroSigningKeys/manifest_private_key.pem
  6. A confirmation dialog showing the private key location appears. Click OK to close it.
Important — Private Key Security
  • The private key file is stored outside the Assets/ folder to prevent Unity from including it in builds. Never move it into Assets/.
  • Exclude OZeroSigningKeys/ from version control with .gitignore or svn:ignore. Committing the private key is a critical security risk.
  • Back up the private key to a secure location. Anyone with this file can create a valid Build Integrity manifest for your project.
  • If you lose the private key, already released builds continue to work. However, the next update can no longer sign a new manifest with the old key. Generate a new key pair, regenerate the integrity manifest, and ship a clean build. The public key, fingerprint, manifest, and signature must match, or Build Integrity verification can fail.

Custom Private Key Path (CI/CD & Team Environments)

The Manifest Signing Private Key Path field does not choose where Generate Key Pair creates a new key. It tells the build and validation tools where to read the PEM private key. Generate Key Pair creates the key at the project default path, then records that path in the config. For CI/CD or team builds, restore the same PEM to a secure path first, then point this field at that path.

  • CI/CD Pipelines — Store the PEM in a CI secret and restore it right before the Unity build. The runner does not need to keep the key on disk permanently.
  • Team Environments — Use a secure mount path or secrets manager that only release builders can access. Every release build machine must use the same PEM.

Validate an existing key pair

To check whether the private key on disk matches the public key stored in OZeroSecurityConfig, click Validate Key Pair. OZero derives the public key from the PEM and compares it with the config. If they do not match, restore the matching private key or generate a new key pair, then rebuild cleanly.

When to regenerate a key pair
  • If the private key is lost or compromised.
  • If Validate Key Pair reports a mismatch (keys are not synchronized).
  • When deliberately rotating keys as part of a scheduled security policy.

After regeneration, already released builds continue to work with their own embedded key and manifest. The next update build must use the new public key, fingerprint, manifest, and signature as one matching set. Regenerate the integrity manifest and ship a clean build.

Dual Fingerprint Key Rotation

When you click Generate Key Pair, the public key is saved in OZeroSecurityConfig, and a fingerprint for that key is recorded in Assets/OZeroSDK/Scripts/Security/BuildIntegrity/OZeroManifestTrustAnchor.cs. At runtime, the SDK first checks that the public key in the asset still matches the trusted fingerprint before it accepts a signed manifest.

Current Key and Previous Key

ExpectedPublicKeyFingerprintHex is the fingerprint for the key used by the current build. PreviousPublicKeyFingerprintHex is an optional transition slot. It does not replace manifest regeneration, and it is not a server-side key manager. The public key in OZeroSecurityConfig, the fingerprint, the manifest, and the signature still need to be generated as one matching set.

Safe Rotation Procedure

  1. Back up the current fingerprint. Open Assets/OZeroSDK/Scripts/Security/BuildIntegrity/OZeroManifestTrustAnchor.cs and copy the ExpectedPublicKeyFingerprintHex value into a temporary note.
  2. Register into the previous key slot. In the same file, paste the value copied in step 1 into PreviousPublicKeyFingerprintHex and save.
  3. Generate a new key pair. Open Window > OZero Security > Config & Dashboard, then click Generate Key Pair in Build Integrity. The new public key and Expected fingerprint are updated automatically. Keep the Previous value from step 2.
  4. Regenerate the integrity manifest and make a clean build. The new manifest and signature must be produced with the new private key.
  5. Keep a transition period. Existing released builds keep using their own embedded key and manifest. The Previous slot is a safety net for rollback or mixed-artifact cases while the new build rolls out. Choose the window based on your update speed, commonly 1-4 weeks.
  6. Clear the previous key slot. Once the usage of the old build has dropped sufficiently, revert to PreviousPublicKeyFingerprintHex = "" and release once more to complete the rotation.
What the Previous slot does

Old shipped builds do not need the new key to keep working. They already carry their own public key, fingerprint, manifest, and signature. The Previous slot is useful for the new release line during a controlled key rotation window. Keep it only as long as you need the transition, then clear it in a later release.

Troubleshooting

Start with the simple checks first: run Generate Key Pair if no key exists, run Validate Key Pair if a key exists, then regenerate the integrity manifest and make a clean build. Most issues come from one of these four items being out of sync: private key PEM, public key in OZeroSecurityConfig, fingerprint in OZeroManifestTrustAnchor, or the generated manifest/signature files.

Symptom 1 — Release build terminates immediately after launch

ExpectedPublicKeyFingerprintHex may be empty. Release builds fail closed when the fingerprint is missing. Fix: run Generate Key Pair, wait for Unity to recompile, then make a clean build. If the value is already filled, run Validate Key Pair and rebuild from an empty output folder.

Symptom 2 — Build halts just before starting with "no manifest signing public key is configured"

Occurs when OZeroSecurityConfig.Integrity.ManifestSigningPublicKey is empty. Fix: Open Window > OZero Security > Config & Dashboard, click Generate Key Pair in the Build Integrity section, and rebuild.

Symptom 3 — Runtime log: "Manifest signing public key does NOT match the pinned trust anchor fingerprint — APK appears to have been repacked with attacker-controlled keys"

Occurs when the public key in OZeroSecurityConfig does not match the fingerprint recorded in OZeroManifestTrustAnchor. This often happens after restoring only part of a key pair or manually editing generated files. Fix: run Validate Key Pair. If it reports a mismatch, restore the matching PEM or generate a new key pair, regenerate the integrity manifest, and make a clean build. If this appears only in a distributed build, also check whether the APK or executable was repackaged.

Symptom 4 — The new build fails manifest verification after key rotation

One part of the rotated set is probably stale: public key, fingerprint, manifest, or signature. Fix: keep the old fingerprint in PreviousPublicKeyFingerprintHex only if you need a transition window, then run Validate Key Pair, regenerate the integrity manifest, clear the old build output, and build again.

Symptom 5 — Local build succeeds but CI build signs with a wrong key or says "private key not found"

CI does not automatically have the local OZeroSigningKeys/manifest_private_key.pem file. Fix: store the PEM as a CI secret and restore it before the Unity build, either to the default path or to the custom path configured in Manifest Signing Private Key Path. Make sure every release runner uses the same PEM, then run Validate Key Pair once in the release environment.

Install Source Settings

Restrict the game to run only if installed from approved stores or paths. Useful for preventing sideloading or repackaged APKs.

Field Type Default Description
Activate Install Source bool true Enable the Install Source module.
allowGooglePlayStore bool true Allow installation through the Google Play Store.
allowSamsungGalaxyStore bool false Allow installation through the Samsung Galaxy Store.
allowAmazonAppstore bool false Allow installation through the Amazon Appstore.
allowHuaweiAppGallery bool false Allow installation through the Huawei AppGallery.
allowOneStore bool false Allow installation through ONE Store (Korea).
allowXiaomiGetApps bool false Allow installation through Xiaomi GetApps.
allowOppoAppMarket bool false Allow installation through the OPPO App Market.
allowVivoAppStore bool false Allow installation through the Vivo App Store.
allowADB bool false Allow installation through ADB (Android Debug Bridge). Enable only for internal testing purposes.
allowDetectionFailedboolfalseAllows startup when the Android installer-package query itself fails. This is different from ADB returning an empty installer value; it means JNI or the platform API could not complete the query. Keep it off for release builds unless you have a tested device-specific reason.
allowUnknownSourcesboolfalseAllows installer packages that are not in the built-in store list and not in customAuthorizedPackages. Use only for regional stores after real-device testing.
enableServerSync (Pro)boolfalsePro only. After local detection, sends the installer package to /v1/install-source/verify so the server can apply a managed allowlist and audit log. If no server rules exist yet, the server allows the source by opt-in behavior.
customAuthorizedPackages List<string> Additional installer package names to allow (e.g., com.yourcompany.launcher).
reportViolationToCallback bool true Send a report to the server if an unauthorized installation source is detected.
logRawInstallerPackage bool true Logs the raw installer package name. Useful during QA when finding the package name for a custom store, but review release log exposure before leaving it on.

Steam Anti-Piracy Settings

Checks Steam execution paths, App IDs, authorization states, and release settings for PC builds distributed via Steam. Standard is local verification, while stronger ownership verification via the Steam server is provided by Pro's server Steam Attestation.

Field Type Default Description
Activate Steam Anti-PiracycheckboxOffSteam Anti-Piracy activation checkbox. The default is Off because Steam App IDs and distribution methods vary by project. Check the status in observe/QA mode first before tightening the release build policy.
expectedSteamAppIdint0Your project's Steam App ID. If you used the development AppID 480 for local checks, be sure to replace it with the actual App ID before release.
requireSteamLaunchbooltrueChecks whether the game was started via Steam rather than directly launching the executable. Keep local development direct-run tests separate from release policies.
requireSteamApiInitbooltrueChecks whether Steam API initialization is successful. Since local development executions might fail depending on Steamworks settings, the final judgment should be made in the actual Steam distribution path.
requireSubscribedCurrentAppbooltrueChecks if the current Steam account owns or has usage rights to the app. This is a local verification; server-side ownership verification is performed in Pro.
requiredDlcAppIdsList<int>Steam DLC App IDs whose ownership should be checked. Add the App ID for each paid or required DLC.
blockSteamAppIdTxtInReleasebooltruesteam_appid.txt is a development-only file for local launch testing without Steam. If it remains in a release build, OZero treats it as a violation because it can allow Steam-bypass launches. Remove it from the project root and build output before distribution.
validateSteamApiDllHashboolfalseVerifies the Steam API DLL hash by comparing it with known SHA-256 values.
allowFamilySharing / allowFreeWeekend / allowTimedTrialbooltrueControls whether to allow Steam Family Sharing, Free Weekends, and Time-Limited Trial authorization states.
requireSteamBuildIdNonZeroboolfalseTreat the build as invalid if Steam reports Build ID 0 or cannot provide a Build ID. Enable this after your Steam depot/build release flow is confirmed.
expectedSteamApiDllSha256HashesList<string>Allowed SHA-256 hashes used when validateSteamApiDllHash is enabled. Add the hash for each Steamworks SDK version, platform, or release branch you ship.
requireValveSignedSteamApibooltrueRequires the Steam API redistributable to match Valve platform identity. Windows uses Authenticode signer validation, macOS uses Valve Team ID validation, and other platforms should use SHA-256 validation as the fallback identity check.
detectKnownSteamEmulatorsbooltrueLooks near the executable for files or folders commonly left by Steam emulators such as Goldberg, CreamAPI, SmartSteamEmu, and ColdClientLoader. If one is found, OZero treats the launch as suspicious.
requireSteamEnvironmentConsistencybooltrueIn release builds, checks that Steam returns a valid individual SteamID and a non-zero Build ID. Preflight client/library path checks are logged as warnings, while invalid SteamID or Build ID becomes a violation.
observeSteamAuthTicketHeuristicbooltrueChecks only the size and basic shape of a local Steam auth ticket as a reference signal. OZero does not log ticket bytes, and this check never blocks the game by itself.
detectionActionOZeroSteamDetectionActionCallbackDecides how far the SDK should go when Steam validation fails. Observe records diagnostics only, Callback calls the game callback, and Block treats the event as a blocking policy. Actual app exit still follows Global Threat Response.
reportViolationToCallbackbooltrueWhen Steam validation fails in Callback mode, sends the event to the normal OZero security callback. Turn this off only for QA builds where you want logs but no game callback.
forceSteamAntiPiracyObserveOnlyboolfalseTemporarily records Steam failures as diagnostics only, without callback or block behavior. Use it while testing unusual Steam launch environments, then turn it off before release.
checkSteamDrmWithServer (Pro)boolfalsePro only. Enables server-backed Steam DRM verification. Use it when Steam ownership should be checked with server evidence instead of relying only on local Steamworks state.
steamDrmVerificationMode (Pro)OZeroSteamDrmVerificationModeOZero ManagedChoose who owns Steam DRM attestation. OZeroManaged lets the SDK call OZero /v1/steam/attest directly, manage the activation cache, and route user-facing states to the default Managed Verification UI after the optional OZero TMP dialog package is imported. CustomerGameServer means your server receives the OZA token and Steam ticket from the client, then calls OZero server APIs.
steamDrmNetworkPolicy (Pro)OZeroSteamDrmNetworkPolicyRequireOnlineRevalidationFresh server revalidation that cannot reach the network or server enters the online-required state. With OZeroManaged and the imported built-in UI package, the retry flow appears without game code.
For Standard Steam Anti-Piracy release builds, use IL2CPP where Unity supports it, keep Build Integrity enabled with the Standard or Strict preset, confirm that the manifest trust-anchor fingerprint is pinned, and rerun Tools > OZero Security > Steam Anti-Piracy > Scan Steam Redistributable whenever Steamworks SDK files change. Treat compatibility diagnostics such as unsupported accessors, non-standard library paths, or verification-unavailable states as QA signals first, not as proof of piracy by themselves.
When Steam Activation / DRM uses OZeroManaged, the first protected launch obtains a valid activation token online through OZero. After that, valid cached tokens and offline grace can allow offline play. If the token has expired, grace has ended, or revalidation is required while the user is offline, the default Managed Verification UI handles the online-required notice, Retry button, retry timeout, and blocked state automatically after OZeroSecurity_BuiltInDialog_TMP.unitypackage is imported.

OZero server-managed Steam DRM

Enable checkSteamDrmWithServer, set steamDrmVerificationMode to OZeroManaged, import OZeroSecurity_BuiltInDialog_TMP.unitypackage, and keep the Managed Verification UI policy in General Settings on a built-in dialog. The SDK sends the Steam auth ticket to OZero, manages the activation token cache, and presents online-required, retry, timeout, warning, or blocked states through the default UI. No callback or retry code is required unless you intentionally replace the built-in UI.

Customer game-server Steam verification

Enable checkSteamDrmWithServer and use CustomerGameServer. Your server issues the audience, 256-bit hex challenge, and session ID; after local validation the client calls RequestGameServerAttestation(...) and sends the callback's OZA token, exact binding values, and Steam Auth Ticket to your server. The server calls /v1/validate and /v1/steam/attest. Keep both server API keys on the server only.

Device Binding Settings

Stores a fingerprint for the first trusted device and compares later launches against it. This helps detect when the same account or protected save data is moved to a different device.

How to use it in operations

In Pro, Device Binding becomes an operations tool. The server can remember which device fingerprints belong to a license, block devices that repeatedly show risk, and help support legitimate device changes without disabling the whole license.

Block devices with repeated risk

Use this after reviewing evidence from Security Events such as SpeedHack, Injection, Install Source, or Build Integrity. A blocked device receives DEVICE_BLOCKED on the next activation, device registration, device verify, or policy check.

Support legitimate device changes

Use a Reset Token when a real player changes phones, reinstalls the OS, replaces hardware, or hits a fingerprint mismatch after a normal environment change. The token is valid for 5 minutes, can be used once, and is bound to the exact license and device.

Limit registered devices

For Pro licenses, maxDevices limits how many active device fingerprints can be registered for one license. A blocked fingerprint does not automatically become a safe reusable slot; reset or delete it only after support verification.

Reset Token support flow

  1. Confirm the player account and why the device reset is needed through your normal support process.
  2. Open Customer Portal → Device Binding, find the target device, and issue a Reset Token.
  3. Send the token only through an authenticated support channel. Do not leave it in public chat, screenshots, or long-lived tickets.
  4. Your game or support UI should pass the token to OZeroDeviceBindingDetector.Instance?.ClearStoredFingerprint(token.Trim()).
  5. After the SDK accepts the token, restart the app or run the protected startup flow again. The current device fingerprint will be registered again.
Do not present Device Binding as a perfect proof of a real person or a permanent hardware identity. Platform identifiers can change after OS resets, privacy setting changes, or hardware replacement. For live games, describe it as an operations layer that raises sharing and abuse costs, and use it together with Build Integrity, Injection, SpeedHack, Install Source, and server validation.
Field Type Default Description
Activate Device Binding bool true Turns on Device Binding checks. When enabled, the SDK creates a local device fingerprint at startup and compares it with the stored value.
hardwareChangeTolerance int (0–3) 1 How many fingerprint components may change while still treating the device as the same device. 0 is strict, while 3 is more forgiving for major hardware or OS changes. The default 1 allows small OS or firmware changes.
storageKey string "ozero_dfp" PlayerPrefs key used by the SDK to store the encrypted local device fingerprint. Change it only if it conflicts with a key your game already uses.
enableServerSync (Pro) bool false Pro only. Registers the fingerprint with /v1/device/register on first use, then verifies it with /v1/device/verify on later sessions. Network or server outages do not block the game, but explicit server rejections such as DEVICE_BLOCKED, FINGERPRINT_MISMATCH, or DEVICE_LIMIT_REACHED are treated as Device Binding violations.
maxDevices (Pro)int0Shows the intended number of devices that may register for one license. 0 means unlimited. The real limit is enforced by the server license record or customer portal policy, so changing this client value alone does not raise the production limit.

Speed & Time Hack Settings

Compares Unity time, native reference clocks, background timers, and web/Pro server time to detect attempts to speed up or slow down gameplay and to catch device-clock changes.

Field Type Default Description
Activate Speed & Time Hack bool true Turns on Speed & Time Hack checks. When enabled, the SDK watches time-flow ratios and device clock changes at runtime.
autoStart bool true Automatically start detection when the game runs. If disabled, you must manually start it using OZeroSpeedHackDetector.StartDetection().
checkInterval float 1.0 s How often the detector compares Unity time with the reference timers. Lower values react faster but may increase CPU cost and false positives.
requiredDetections int 3 How many abnormal samples must appear in a row before OZero treats the case as a violation. Increase this on unstable devices to reduce false positives.
ratioTolerance float 0.15 Time-flow difference that is still treated as normal between Unity time and the native reference timer. Start with the default and adjust only if real gameplay shows false positives.
maxAllowedRatio float 4.0 Maximum allowed time-flow ratio. If the ratio goes past this value, OZero treats it as a strong speed-hack signal. Most games should keep the default.
detectSlowHack bool false Also detects slow-motion manipulation, not only speed-ups. Default is false. Enable only after testing normal slow motion, cutscenes, and intentional speed changes in your game.
enableTimeScaleDetection bool true Checks whether Time.timeScale was changed by unapproved code or memory editing. Use OZeroTime.timeScale for intentional game-speed changes.
hackDetectMultiplier float 1.3 A sample far above maxAllowedRatio is counted as a stronger signal. Most projects should keep the default.
enableThreadTimerCheck bool true Uses a background thread timer as an additional reference clock. This helps catch tools that only manipulate the main thread.
useWebTimeValidation bool true Cross-checks device clock changes using HTTPS Date headers or Pro server time. Default is true.
webSyncInterval float 15 s How often to compare against web or server time. Very short intervals increase network traffic.
webRatioTolerance float 0.15 Time-flow difference that is still treated as normal between device time and web/server time. Validate on real devices with regional network latency in mind.
timeOffsetTolerance float 60 s Maximum absolute difference allowed between the device clock and web/server time before OZero treats it as time manipulation.
focusIgnoreTime float 4 s Time (in seconds) to ignore immediately after the app regains focus. Prevents false positives caused when the OS suspends the app.
loadingGraceTime float 6 s Grace period after app startup or scene loading. It prevents heavy loading from being mistaken for time manipulation.
lagSpikeIgnore float 0.5 s Drops samples whose frame delta is larger than this value. This keeps real lag spikes from being counted as time manipulation.
buildFailIfTimeScaleTamperedbooltrueFails the build/verification phase if protected code appears to change Time.timeScale directly outside the approved policy.
timeScaleTamperExemptionsList<string>Script or method name patterns that may directly change Time.timeScale. Register only reviewed code such as pause, bullet-time, or cutscene systems, and keep the list small.
webTimeUrlsstring[]HTTPS addresses used for web/server time checks. Add two or more addresses you operate or trust so one blocked address does not stop the check.
minSuccessfulEndpointsint2Minimum number of addresses that must return a valid Date header before OZero trusts the time for that round. Do not set this higher than the number of configured addresses.
maxConsecutiveFailuresint6Runs the onWebTimeUnavailable policy after this many failed web/server time rounds in a row. This gives temporary network errors room before they become a security signal.
onWebTimeUnavailableWebTimeUnavailablePolicyWarnOnlyPolicy used when web/server time cannot be checked for several rounds. WarnOnly logs and continues. Strict treats repeated failure as suspicious and raises a SpeedHack callback. Silent leaves no log, so reserve it for special tests.
detectTimeHackbooltrueChecks device clock changes and web/server time differences. This catches system-clock manipulation separately from speed-ratio checks.
webSyncJitterPercentfloat20%Spreads web/server time checks around the configured interval so devices do not all call at once. For example, 20% makes a 15-second interval run roughly between 12 and 18 seconds.
sustainedLagThresholdfloat0.15If the recent average frame time is slower than this value, OZero first treats it as real lag and avoids confirming time-hack evidence immediately. The default 0.15 seconds is roughly 6-7 FPS.
sustainedLagGraceDurationfloat3 sHow long OZero pauses strict timing judgment after sustained lag is detected. The pause is extended while lag continues and is capped by the runtime at 10 seconds.
overloadStrictMultiplierint3In Strict mode, waits longer when failures look like plain timeouts rather than clear server rejection. Default 3 means the callback fires after up to maxConsecutiveFailures times 3 timeout-like failures.
enableRemoteSpeedHackConfig (Pro)boolfalseLets Pro server policy adjust selected Speed & Time Hack thresholds without an app update. If the server is unavailable, local Inspector values remain active, so protection does not turn off.
remoteSpeedHackConfigIntervalfloat300 sHow often to refresh Pro remote Speed & Time Hack settings. 0 means fetch once at app startup only; positive values check periodically for new policy.
remoteSpeedHackConfigJitterPercentfloat20%Spreads Pro remote-config refresh timing so many devices do not call the server at the same moment.
enableSignedServerTime (Pro)boolfalseUses signed Pro /v1/time responses as the preferred trusted time source after Pro activation is available. Enable it after server keys and endpoint tests are complete.

Use OZeroTime.timeScale instead of Time.timeScale

When the Speed & Time Hack protection module is enabled, project code must not directly modify Unity's built-in Time.timeScale. If code bypasses OZero and writes to it directly, the OZero detector may treat the change as suspicious runtime time manipulation and run the configured response policy.

Exception policy (TimeScaleTamperExemptions)

OZeroSecurityConfig.TimeScaleTamperExemptions is an exception list for scripts that still need direct Time.timeScale access. Keep this list as small as possible.

Use exemptions only for verified third-party plugins or legacy adapter scripts where direct Time.timeScale access cannot be avoided because of the existing structure.

All other project gameplay code should use OZeroTime.timeScale without exception. Use it for pause, slow motion, cutscene speed control, fast-forward, and any other intentional game-speed changes.

using OZeroSDK.Security;

// Correct: the detector knows this is an intentional game-side change.
OZeroTime.timeScale = 0.5f;

// Avoid: this bypasses OZero's expected time-scale tracking.
Time.timeScale = 0.5f;
Before release, run Tools > OZero Security > Check Time.timeScale Usage and replace direct writes with OZeroTime.timeScale wherever possible.

Prevent unintended Watchdog termination during long loading

OZero's native Watchdog checks that Unity's main thread is still running by receiving periodic heartbeat updates. In release builds the heartbeat deadline is about 10 seconds on every platform (after the start-up grace). When the deadline passes, the Watchdog first looks at what the main thread is doing: a thread that is blocked and consuming no CPU (a long synchronous load, a log flush, disk I/O, a virtual machine pausing the thread) is treated as a stall and only logged, while a game that keeps running without sending heartbeats is treated as tampering and terminated according to the configured response policy. A process that stays stalled for more than five minutes is closed as hung.

This can happen during legitimate work such as large scene loading, synchronous asset decompression, shader warmup, or Addressables preparation when the main thread is intentionally blocked for several seconds.

Wrap that trusted loading boundary with OZeroWatchdog.BeginLoadingGrace(maxGraceMs). The grace starts when loading begins and ends immediately when the scope is disposed or End() is called, so you do not need to know the exact loading time in advance.

using OZeroSDK.Security;
using UnityEngine.SceneManagement;

public void LoadLargeScene()
{
    using (OZeroWatchdog.BeginLoadingGrace(60000))
    {
        SceneManager.LoadScene("Battle", LoadSceneMode.Single);
        // Grace ends as soon as the using scope exits.
    }
}

public void WarmUpLargeAssets()
{
    OZeroWatchdog.RunWithLoadingGrace(() =>
    {
        BuildLargeRuntimeCache();
    }, 60000);
}
Caution: Do not misuse Loading Grace.

This feature is a temporary grace period that prevents the app from being terminated during long, legitimate loading work. It cannot be used for security bypasses or to keep the app running indefinitely.

If a heavy loading task may exceed the allowed time, split it into smaller steps or use Unity Coroutines / async loading so the screen and main thread do not stay frozen.

Physics Hack Detector

Attach this component to each moving player object.
OZeroSecurityConfig.PhysicsHack only controls the global on/off switch and Pro telemetry. Speed limits, distance tolerance, wall-crossing checks, and acceleration checks are configured on each OZeroPhysicsHackDetector component. Attach it to the player prefab, tune the values for the real movement rules of that character or vehicle, and call Initialize(playerId) after spawn.
Field Type Default Description
physicsHack.useGlobalPhysicsHackbooltrueGlobal on/off switch for all Physics Hack components. Turn it off only when you intentionally want every physics movement check to stop.
physicsHack.enableServerTelemetry (Pro)boolfalsePro only and disabled by default. This explicit project opt-in controls both general security-event telemetry and the detailed PhysicsHack stream. Turning it off stops new telemetry events, and a server policy can disable but never enable transmission without local consent.
physicsHack.telemetryThrottlePerMinute (Pro)int30Maximum number of PhysicsHack telemetry events this client can send per minute. This prevents a bad threshold from flooding the server.
Field Type Default Description
maxAllowedSpeed float 15 u/s Maximum normal movement speed for this object, in Unity units per second. Set it to the fastest legitimate speed this character or vehicle can reach in the game.
distanceTolerance float 2.0 u Extra distance allowed beyond the movement distance calculated from maxAllowedSpeed. Use it to absorb network position correction, physics rounding, and small controller jitter.
obstacleLayer LayerMask Layers treated as walls or solid obstacles. OZero checks the path from the previous safe position to the current position; if that path crosses one of these layers, it can be treated as wall clipping.
checkInterval float 0.05 s How often this component checks position, wall crossing, and acceleration anomalies. Lower values react faster but use more CPU.
maxDeltaTimeCap float 0.1 s Maximum frame time used in the distance calculation. This prevents one long frame from giving a cheater a very large allowed movement distance.
violationThresholdint2Number of bad checks required before the callback fires. A normal check lowers the counter, so one small physics glitch does not immediately become a violation.
castRadiusfloat0Radius used for wall-crossing checks. 0 lets OZero estimate it from a CharacterController or CapsuleCollider; if none is found, it falls back to a line check.
enableAccelerationCheckbooltrueChecks sudden Rigidbody speed changes. Consider disabling it for kinematic objects, server-authoritative movement, or custom movement that normally changes velocity outside the physics solver.
maxAllowedAccelerationfloat60Maximum speed change allowed between checks. Raise this for dash, knockback, launch pads, vehicles, or other legitimate burst movement.
enableLogbooltrueShows debug logs from this component while tuning. Serious setup issues, such as an empty obstacle layer, still warn even when this is off.

Injection Detector Settings

Detects programs that get inside the running game: injected native modules, executable private memory, inline hooks, remote-thread style injection, high-risk process handles, and WebGL runtime tampering. Normal overlays and capture tools enter the game the same way, so the detector identifies every module by file hash and signer and lets you decide per module.

Start with the default settings.
Allow a module only when a normal overlay, recorder, partner SDK, or module shipped with your game is detected. Confirm the module name, file hash, and signer from Failure Diagnostics or the Pro portal first. Never allow a module just because it appears often — cheat tools are common too.
Field Type Default Description
Activate Injection & HookingcheckboxOnDashboard checkbox that maps to useInjection. In player builds it enables the native injection checks; development builds use a softer diagnostic flow, and the Editor normally skips the detector.
injectionWhitelistEntriesOZeroInjectionWhitelistEntry[]emptyLocal trusted module list available in all tiers. Each entry allows one specific module by SHA-256 file hash and optional signer fingerprint. Add only modules shipped with the game or verified through QA, diagnostic files, Pro telemetry, or OZero support guidance.
enableServerWhitelist (Pro)boolfalsePro only. Downloads the signed allow/block list built from your portal decisions and OZero's global verdicts, and merges it with the SDK baseline and local list. Allowed modules are silenced; blocked modules close the game immediately. The verified list is cached for offline starts; if the server is unreachable, protection stays on with the last known list.
serverWhitelistRefreshIntervalfloat0 sHow often a running game re-downloads the Pro decision list. 0 fetches once at start-up only. Shorter intervals bring portal decisions to players faster at the cost of a little more traffic; the list is also refreshed on the next start.
requireSignerForNativeWhitelistboolfalseRequires Windows PE and Apple Mach-O whitelist entries to include a signer fingerprint as well as the file hash. Stronger, but use it only after you can collect clean signer data. Android/Linux shared libraries normally remain hash-only.
enableRemoteInjectionConfig (Pro)booltruePro only. Lets the portal override selected Injection settings, such as scan intervals, signer requirements, and individual probe switches, without shipping a new app build.
remoteInjectionConfigIntervalfloat300 sHow often the Pro remote Injection config is checked again. 0 means the SDK fetches it only once during startup.
enableWindowsModuleIdentityScanbooltrueIdentifies every module that appears after start-up by file hash and, on Windows/macOS, signer fingerprint, on all native targets (the legacy field name says Windows). iOS/macOS treat images inside the app's own bundle as the game's code; Android/Linux identify shared objects by hash. See How the detector identifies a module.
scanIntervalSecondsfloat1 sMain Injection scan interval. Lower values detect faster but add more runtime overhead. The runtime clamps this value to a safe range.
windowsModuleIdentityScanIntervalSecondsfloat5 sSeparate interval for the heavier native module identity scan. Increase it if module enumeration or hash/signer checks are too expensive on your target device.
scanJitterPercentfloat20%Spreads each periodic Injection check slightly around the configured interval. This keeps checks from running at an easy-to-predict exact second.
enableExecutablePrivateMemoryScanbooltrueDetects executable private memory that was not loaded as a normal module. This catches shellcode-style payloads, but a bare executable region only accumulates evidence; it never closes the game on its own. The scan is switched off automatically on Mono scripting-backend builds on every platform, because the Mono JIT creates exactly this kind of memory.
enableInlineHookScanboolfalseChecks whether sensitive native API entry points look patched. This is useful for strict builds, but overlays and security software can hook APIs, so enable it only after compatibility testing.
enableThreadStartAddressScanbooltrueChecks whether a native thread starts from suspicious memory outside trusted loaded modules. This helps catch remote-thread style injection on supported platforms.
enableExternalProcessHandleScanbooltrueChecks for external processes holding high-risk handles to the game process, such as debugger or memory editor attach states. Supported mainly on Windows.
detectionConfidenceThresholdint70Minimum confidence score for a strong Injection signal to be treated as a violation immediately. Lower-confidence signals can still be handled by consecutive or sliding-window checks. Clamped to 60–100: below 60 every in-process JIT engine (WebView, Lua, Mono) would look like a violation.
enableWebRuntimeTamperScan (WebGL)booltrueWebGL-only browser runtime checks. WebGL cannot use Native C++ module scanning, so these probes look for browser-side tampering signals and should be treated as supplementary client-side evidence.
webRuntimeScanIntervalSeconds (WebGL)float1.5 sBase interval for WebGL runtime checks. The runtime clamps it to 0.5-30 seconds so the browser is not checked too aggressively.
webRuntimeScanJitterPercent (WebGL)float20%Spreads WebGL runtime check timing around the configured interval so checks do not run at a perfectly predictable moment.
WebGL probesboolstrueIndividual WebGL probe switches for DevTools, clock hooks, network hooks, WebAssembly hooks, storage hooks, and crypto API hooks.

How the detector identifies a module

Every few seconds the detector walks the complete list of modules loaded in the game process and compares it with the set it saw at start-up. A new module is identified by its file hash and, on Windows and macOS, by the fingerprint of the certificate that signed it. Rules look at the module itself, never at the folder it was installed from, so a normal program is not flagged because of its install path.

Platform What counts as the game's own code
WindowsModules present at start-up that pass the same rules as at runtime, the operating system's own components (System32, SysWOW64, WinSxS), and the game's own native modules — recognised by the hash list the build signs into the integrity manifest, never by their folder. Overlays and helpers whose certificate chain validates for a known vendor (Steam, Discord, NVIDIA, RivaTuner, Nahimic, OBS, Epic, Ubisoft, EA, Overwolf, Medal, NVDA) are recorded as silenced observations; any other module signed with a certificate the operating system trusts is never terminated by itself and appears in the portal's pending list instead. A native file in the game folder that is not in the signed list is a Build Integrity violation at start-up.
iOS / macOSAny image that belongs to the app's own .app bundle, plus Apple platform images. Nothing has to be generated at build time. This needs iOS 14.0 or later; the Editor preflight fails for a lower target.
Android / LinuxShared objects present at start-up that pass the same rules as at runtime, system and engine runtime libraries, the Steam overlay, and the application's own libraries — on Linux recognised by the signed build inventory (never by folder), on Android by the installed package directory, which only the OS can write. The Android system WebView provider counts as a platform component. Executable memory that belongs to no file is reported by the same pass but only accumulates; it never terminates on its own. Linux host layers and Proton follow the Build Integrity policy above (Monitor by default).

Each check returns one of three answers per detection family: detected, scanned clean, or not due yet. Only real samples move the counters; a check that did not run never resets a previous detection, and a check that could not run at all is reported as a scanner health problem rather than a clean result.

Pro: allow or block observed modules from the portal

With enableServerWhitelist on, a Pro build downloads one signed decision list at start-up and again at every serverWhitelistRefreshInterval. The list merges the decisions your team makes in the customer portal (Injection → Detection status → Observed modules) with OZero's own verdicts drawn from data across all customers.

Decision What the game does
AllowThe module (matched by hash and signer) is added to the native trusted list and no longer treated as a threat on any device of the project.
BlockAny game that has this module loaded is closed immediately, without waiting for repeated detections. Reserved for confirmed cheat tools.
WatchNot sent to the game. The module keeps being recorded so the team can decide later with more evidence.

Scanner unavailable (abort code 0x15)

If the native scanner itself cannot run — the configuration could not be applied, native scans keep failing, or the managed and native halves disagree on the contract — the SDK reports ModulationType.InjectionScannerUnavailable (value 10, abort code 0x15, message key injection_scanner_unavailable) and closes the game even when ForceQuitOnDetection is off. This is not an attack detection: a scanner that is silently broken would leave the game unprotected. Show players a support code such as OZ-SEC-15 and keep the abort code in your logs.

PlayerPrefs Encryption

For new keys that need protection, store values with OZeroSafePlayerPrefs instead of Unity PlayerPrefs. The common Get/Set, HasKey, Delete, and Save names are familiar, but encrypted data is not compatible with existing plain PlayerPrefs data.

using OZeroSDK.Security;

// Save a value
OZeroSafePlayerPrefs.SetInt("score", 4200);
OZeroSafePlayerPrefs.SetFloat("volume", 0.8f);
OZeroSafePlayerPrefs.SetString("username", "Hero");

// Read a value
int    score    = OZeroSafePlayerPrefs.GetInt("score", 0);
float  volume   = OZeroSafePlayerPrefs.GetFloat("volume", 1.0f);
string username = OZeroSafePlayerPrefs.GetString("username", "");

Save File Encryption

To encrypt save files, use OZeroSV_File instead of File.ReadAllText / File.WriteAllText. Files are automatically encrypted on write and decrypted on read. It also checks for tampering upon loading.

using OZeroSDK.Security;

string path = Application.persistentDataPath + "/save.json";

// Write encrypted file
OZeroSV_File.WriteAllText(path, jsonString);

// Read and decrypt file
string json = OZeroSV_File.ReadAllText(path);
Important: Do not change developerSecret after release. developerSecret is the base value used to derive the encryption key for OZeroSafePlayerPrefs and OZeroSV_File data. If this value changes after release, protected data saved by previous versions cannot be decrypted by newer builds.

4 In-Game Variable Protection (Secure Types)

Secure Types replace regular C# variable types with encrypted types. Values are stored in the Native C++ heap, meaning tools like Cheat Engine cannot find them even if they scan the memory. Just change the type name, and the rest of the code will work exactly the same.

Unity Inspector showing OZeroSV_Int and OZeroSV_Float fields

Example code

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using OZeroSDK.Security;

public class PlayerStats : MonoBehaviour
{
    [SerializeField] OZeroSV_Int Gold = 5000;
    [SerializeField] OZeroSV_Float Speed = 3.5f;
    [SerializeField] OZeroSV_Int HP = 1000;
}

Supported types

Before After OZero
intOZeroSV_Int
longOZeroSV_Int64
uintOZeroSV_UInt
ulongOZeroSV_UInt64
shortOZeroSV_Short
ushortOZeroSV_UShort
byteOZeroSV_Byte
floatOZeroSV_Float
doubleOZeroSV_Double
decimalOZeroSV_Decimal
boolOZeroSV_Bool
stringOZeroSV_String
Vector2OZeroSV_Vector2
Vector3OZeroSV_Vector3
byte[]OZeroSV_Buffer
Secure Types use the OZeroSDK.Security namespace. Add the using directive to scripts declaring these types.

7 Security Event Handling (Optional)

By default, OZero either terminates the app or logs the event according to the configured response policy when a threat is detected. If you need to directly display a warning screen, send a custom server log, or perform save processing right before termination, you can register a callback. The callback passes the OZeroSecurityEvent containing the modulation type, abort code, message key, detailed message, and whether termination is pending.

using UnityEngine;
using OZeroSDK.Security;

public class SecurityHandler : MonoBehaviour
{
    void OnEnable()
    {
        // RegisterUserCallback runs on the user chain only.
        // The built-in default handler runs independently and cannot be silenced.
        OZeroSecurityManager.Instance.RegisterUserCallback(OnThreatDetected);
    }

    void OnDisable()
    {
        OZeroSecurityManager.Instance.UnregisterUserCallback(OnThreatDetected);
    }

    void OnThreatDetected(OZeroSecurityEvent evt)
    {
        // evt contains Type, AbortCode, AbortCodeHex, MessageKey, Message, and WillAbort.
        Debug.LogWarning(
            $"OZero threat: {evt.Type} {evt.AbortCodeHex} {evt.Message}");

        switch (evt.Type)
        {
            case ModulationType.SpeedHack:
                // e.g. kick the player, show warning, report to server
                break;

            case ModulationType.BuildIntegrity:
                // evt.WillAbort is usually true for fatal build integrity violations.
                break;

            case ModulationType.Injection:
                break;
        }

        if (evt.WillAbort)
        {
            // Last chance to flush your own analytics or save state.
        }
    }
}

The complete lists for OZeroSecurityEvent, ModulationType, and OZeroAbortCode are documented in the API Reference.

If evt.WillAbort is true, the app will terminate after the callback according to the current response policy. In this case, only perform brief custom analytics flushes or save processing.
Detection Event Delivery Flow

When a threat is detected, OZero first applies the SDK's default response policy and also delivers the same security event to callbacks and Inspector events registered by the project. Register a callback if you want to display a custom warning screen or write server logs. Whether the app will terminate can be checked via the Config Dashboard's Response settings and the evt.WillAbort value.

Portal policy callback

Customer Portal policies can be operated in stages. Observe only records evidence, Callback sends a server-issued policy action to the game, and Device Block blocks the selected device on later server verification. Use Callback when you want the game to show a warning, limit matchmaking, request re-login, or route the player to support before using a stronger device block.

using UnityEngine;
using OZeroSDK.Security;

public class PolicyActionHandler : MonoBehaviour
{
    void OnEnable()
    {
        OZeroSecurityManager.Instance.RegisterUserPolicyActionCallback(OnPolicyAction);
    }

    void OnDisable()
    {
        OZeroSecurityManager.Instance.UnregisterUserPolicyActionCallback(OnPolicyAction);
    }

    void OnPolicyAction(OZeroPolicyActionEvent evt)
    {
        Debug.LogWarning(
            $"Policy callback: {evt.Module}, score={evt.Score}, reason={evt.Reason}");

        if (evt.Score >= 80)
        {
            // Show your own UI, limit sensitive actions, or ask the player to reconnect.
        }
    }
}

Next Steps

The core OZero protection features are now running. Please check the API Reference for detailed information on all classes, methods, and configuration options.

Troubleshooting Reference

Use this section when an OZero dialog appears, a security log is reported, or the app closes for a security reason. Start with the code shown on screen or in the log, then follow the first checks below.

Support Codes

Support codes are short labels shown in OZero dialogs and logs. When a player sends this code to support, the development or QA team can quickly identify which broad area to check. OZ-SEC-* means a security event was reported, and OZ-MV-* means an online or managed verification state needs attention.

Code Category What to check
OZ-SEC-01Memory protectionCheck whether protected values were changed by an unsupported path, a test tool, or an incorrect Secure Types integration.
OZ-SEC-02Injection or hookCheck whether an overlay, debugger, modding tool, or other external program was attached. Add exceptions only after QA confirms the program is trusted.
OZ-SEC-0ABuild integrityCheck whether the build, manifest, signing information, native variant, or packaged files changed after the release build was prepared.
OZ-SEC-0CSpeed or time changeCheck speedhack tools, device clock changes, direct Time.timeScale writes, and legitimate slow-motion or pause flows.
OZ-SEC-0EDevice or install policyCheck the install source, store package identity, emulator/root/jailbreak policy, and device-binding support process.
OZ-SEC-0FPhysics checkCheck whether movement limits, collision layers, dash, knockback, or vehicle movement are tuned for the actual game rules.
OZ-SEC-10Runtime environmentCheck whether the app is running in a supported device, browser, emulator, debugger, or platform test environment.
OZ-SEC-13Steam verificationCheck Steam launch state, AppID, ownership verification, required Steamworks files, and network connection.
OZ-SEC-15Injection scanner unavailableNot an attack. The native injection scanner could not run (configuration not applied, repeated native scan failures, or a managed/native contract mismatch). Check that the SDK and native binaries come from the same package and reinstall the game before escalating.
OZ-SEC-1FUnknown categoryCollect the platform, SDK package version, native ABI, Player log, ozero_abort.txt, and exact reproduction steps.
OZ-MV-LOCALManaged verificationCheck license activation, server/network access, registered app identity, platform signing information, and the currently applied variant manifest.

Abort Codes

Abort codes are stable categories used in logs, callbacks, and OZ-SEC-* support codes. They tell the development team which protection area responded without exposing detailed evidence to the player.

Code Category Meaning
0x01Memory protectionProtected memory value changed unexpectedly.
0x02Injection or hookUnexpected module, hook, or runtime injection signal detected.
0x0ABuild integrityBuild integrity validation failed.
0x0CSpeed or time changeSuspicious execution speed, time scale, system clock, or trusted-time anomaly detected.
0x0EDevice or install policyDevice binding or install-source policy rejected the current environment.
0x0FPhysics checkAbnormal physics behavior exceeded the configured policy.
0x10Runtime environmentUnsupported or unsafe runtime environment detected.
0x13Steam verificationSteam ownership or ticket validation failed.
0x15Injection scanner unavailableThe injection scanner itself could not run; the SDK fails closed instead of running unprotected.
0x1FUnknown categoryA security event did not match a more specific public category.

For API fields and callback examples, see OZeroAbortCode & Event Messages.

Resolution Workflow

Step Action Expected evidence
1Record the support code shown on screen or in the log, plus the platform.The screenshot or ticket should include the code, OS, Unity version, SDK package version, and whether the build is Development or Release.
2Check ozero_abort.txt and the Player log first.These files can still help when the app closes before a popup appears.
3If the issue is reproducible in QA, enable Enable Failure Diagnostics, reproduce once, then disable it again.The latest ozero_*_failure.log helps identify which protection area responded. Use this file only for QA or support investigation.
4Run Window > OZero Security > Check Setup before changing policies.Preflight can catch missing required packages, manifest/signing mismatch, platform settings, ProGuard/R8 settings, native plugins, and obvious license setup issues.
5For Pro or managed verification cases, compare portal registration with the actual build information.Confirm package/app ID, platform signing information, SDK package, native ABI, active variant manifest, license tier, server connection, and any downgraded or limited state.
6After the fix, rerun the matching platform QA scenario.Capture survival timing, Managed UI visibility, simulated or real attack result, popup countdown, and final logs before closing the ticket.