Keeping Secrets Out of Your Build
What a Unity player build on PingCore may carry, how the build guard stops credentials and debug tools shipping, and where the Editor plugin keeps your API key and push token.
A player build is public the moment it ships: anyone with a copy can read every string in it. This page lists what a build may carry, how the build guard checks it, and where the Editor plugin keeps your credentials.
What may ship
A build may carry two things, both in your PingCoreClientSettings asset:
Discovery app public ids (
dscp_). They are not secrets: a client needs one to find game servers. Connect in the PingCore window writes your fleet app's id when you pick the fleet.An open community app's heartbeat token, only for games whose players host their own game servers, and only after Confirm for build has checked it.
Nothing else ships. Never put these in an asset, a scene, a script or a default value:
usr_: an API key;cdnpush_: a CDN source's push token;dsc_: any other Discovery app token.
The player token your game gets from Discovery at runtime is not build content. The SDK keeps it in PlayerPrefs by default (DiscoveryClientOptions.TokenStore), which is fine for a short-lived token that belongs to one player. Never keep any other credential there.
The build guard
The build guard comes with the Editor package. It runs on every player build, including builds you start from File > Build Profiles, and it cannot be switched off. It checks your sources and assets before the scripts compile, the assets the build packed once the player is written, and every byte of the output at the end.
A build fails with one of these reasons:
secret_literal: a token-shaped string, that isusr_,sys_,cdnpush_ordsc_followed by 16 or more letters or digits, or a heartbeat token that was not confirmed.editor_assembly: aPingCore.Editorassembly is in the build.instrumentation_in_plain_build: a release build carries a tool your build guard rules keep out.output_unscannable: the output is an archive the guard cannot read, and there was nothing to scan in its place.scan_error: a check could not finish, such as an unreadable file or a rules file it cannot parse.
Unity reports a failed build with "PingCore build guard (stage) rejected the build:" followed by the reason. Each finding names the file and position, never the token. When the build fails after the player was written, the guard deletes the output.
Every build leaves its verdict, pass or fail, in Library/pingcore-build-guard.json. A script that drives builds should require verdict pass with stage postprocess for its output path.
The guard cannot see inside an archive (.apk, .aab, .ipa, .zip and similar), so for those it scans the compiled player code instead. It cannot recognise credentials that have no prefix either. Keep every key and token out of the project in the first place.
Keeping your own tools out of a release build
Debug tools, cheat commands and test harnesses must not reach players either. Name them in ProjectSettings/PingCoreBuildGuardRules.json and the guard fails any release build that carries them. Without the file there are no such rules.
{
"restrictedAssemblyPrefixes": ["MyGame.Debug."],
"instrumentationDefines": ["MYGAME_DEBUG"],
"instrumentedOutputFolder": "Builds/Instrumented"
}restrictedAssemblyPrefixes: an assembly whose name starts with one of these never ships in a release build.instrumentationDefines: a build with one of these scripting defines is an instrumented build.instrumentedOutputFolder(optional): a project folder outsideAssets,Packages,ProjectSettings,Library,UserSettings,TempandLogs. Only a build written inside it may carry the restricted assemblies and defines. Leave it out to refuse them everywhere.
Give each tool assembly a Define Constraints entry such as MYGAME_DEBUG, so a release build does not compile it at all; the guard catches what slips through. A build that breaks a rule fails with a Console line starting "[PingCore build guard] instrumentation_in_plain_build:" that names the assembly or define.
The guard reads the file strictly. An unknown key, a key given twice or a value of the wrong type fails every build with scan_error, so a typo never switches a rule off.
Build in the PingCore window always makes a release build. To build a dedicated server with your tools in, run -executeMethod PingCore.Editor.Cli.BuildServer.Run without -buildProfile, passing -pingcoreVersion, -pingcoreScene (repeat per scene), -pingcoreProduct, -pingcoreDefine and -pingcoreOutputRoot (a folder under Builds/). Player builds use your own build script; the guard applies the same rules.
Confirm for build
Only a game whose players host their own game servers in an open community app needs this. Self-Hosted Game Servers and Listen Hosts explains when.
Open Window > PingCore and expand Player hosting.
Check that Community app names your open app. Click Change to pick another.
Paste the app's heartbeat token into Set token and press Enter. The field empties at once.
You should see "Heartbeat token saved in the asset. Press Confirm for build before building a player with it."
Click Confirm for build.
You should see "Confirmed: the token is the heartbeat token of open app "app name". Builds may now carry it."
Confirm checks with your workspace that the app is yours, enabled and open, and that exactly one of its active heartbeat tokens ends in the same last four characters (the workspace never shows a whole token). It records a digest of the whole token, never the token, in ProjectSettings/PingCoreBuildGuard.json, and the build guard lets that one token through.
To ship no token at all, leave the field empty. A listen host then reads its heartbeat token at runtime from the PINGCORE_DISCOVERY_TOKEN environment variable.
Where the plugin keeps your key and push token
The plugin holds your usr_ API key and the push token of each CDN source it pushes to.
On Windows, both go to Windows Credential Manager, as
PingCore/app.pingcore.io/usrandPingCore/app.pingcore.io/cdnpush/<source id>.On macOS and Linux, and on Windows when Credential Manager cannot be used, the plugin keeps them in Unity's
EditorPrefs: outside your project, but not encrypted. Connect shows a warning starting "Stored in EditorPrefs, not the OS credential store:" while it does.This session only, ticked before Sign in, keeps the key in memory until the Editor quits. Push tokens always go to the persistent store.
Neither ever lands in your project. The window never shows a push token, passes it to pingctl through the environment rather than the command line, and masks tokens and keys in everything it logs.
Signing out
Under Connect, click Sign out.
You should see "Signed out; the key was deleted from the credential store."
Sign out deletes your API key. Stored push tokens stay. To stop a push token working everywhere, open its CDN source in the panel and click Regenerate under Push Token (pingctl), then delete the old entry from Credential Manager (or EditorPrefs) if you no longer want it on this machine.
If a key or token was ever printed, committed or pasted where others can read it, replace it: delete the API key in the panel and create a new one, or regenerate the push token.