Every field in nebula.config.json — types, defaults, and what it does.
Nebula is driven by a JSON config file (nebula.config.json) passed with --config. This is the
complete list of fields. All are optional except inputs; unknown keys produce a warning rather
than being silently ignored.
{
"inputs": ["bin/Release/net8.0/MyApp.dll"],
"outputDirectory": "bin/Release/net8.0/obf",
"preservePublicApi": true,
"controlFlowObfuscation": true,
"encryptStrings": true
}
Editions. The Free edition does identifier renaming, up to 2 encrypted strings and up to
2 control-flow methods. Everything else (unlimited strings/control-flow, method & resource
encryption, anti-tamper, anti-debug, metadata hardening, constants, aggressive naming,
cross-assembly rename, signing, PDB output, plugins) is Licensed; aggressive control-flow
intensity and watermarking are Enterprise. See Editions.
| Key | Type | Default | Description |
|---|
inputs | string[] | — (required) | Assembly path(s) to obfuscate. List all interdependent assemblies together for cross-consistent renaming — see Multiple assemblies. |
outputDirectory | string | <inputDir>/nebulated | Where obfuscated assemblies, symbol maps and reports are written. |
allowInPlace | bool | false | Safety guard: writing over the input assembly is refused unless this is true, so a mistyped path can’t destroy your source assembly. |
copyRuntimeConfig | bool | true | Copy each input’s *.runtimeconfig.json / *.deps.json next to the output so a framework-dependent app runs from the output folder. |
verifyOutput | bool | true | Re-check the transformed module for dangling references before writing and refuse to emit output that wouldn’t load. Leave on. |
schemaVersion | int | 1 | Config schema version, so older files get a clear upgrade warning. |
Renaming
| Key | Type | Default | Description |
|---|
preservePublicApi | bool | false | Keep public/protected type & member names; rename only internal/private. Turn on for a library referenced by code outside the run; off to rename everything eligible. |
autoDetect | bool | true | Automatically preserve names required for correctness — reflection/serialization/DI/XAML targets and [Obfuscation]-marked members. Leave on. |
include | string[] | [] | Allowlist of type full names eligible for renaming. When non-empty, only these types (and their members) are renamed; everything else is preserved. |
exclude | string[] | [] | Force-preserve names. A type full name preserves the type and all members; "Namespace.Type.Member" preserves one member. |
excludeNamespaces | string[] | [] | Force-preserve whole namespaces: any type whose namespace equals or starts with an entry (e.g. MyApp.Api) keeps its name and its members’. |
renameResources | bool | false | Rename embedded resource names and update references (incl. type-associated .resources so ResourceManager still resolves). |
aggressiveNaming | bool | false | Use hard-to-read Unicode-confusable identifiers instead of short ASCII names. Still deterministic and collision-free. |
crossAssemblyRename | bool | false | In a multi-assembly run, rename types/members shared across the input assemblies and rewrite every cross-assembly reference. Requires all referencing assemblies to be inputs — see Multiple assemblies. |
String encryption
| Key | Type | Default | Description |
|---|
encryptStrings | bool | false | Encrypt string literals in IL and decrypt at runtime with a per-build key. |
encryptStringsInclude | string[] | [] | Allowlist of exact literals to encrypt. When non-empty, only these are encrypted. Discover them with nebula inspect --strings. |
excludeStrings | string[] | [] | Exact literals to leave un-encrypted (e.g. license text). |
Control flow & code protection
| Key | Type | Default | Description |
|---|
controlFlowObfuscation | bool | false | Flatten method control flow into a dispatcher state machine. Works for all method shapes, including try/catch/finally (the top level and each try body are flattened; nested handlers are kept atomic). Anything not provably safe to move is left intact. |
controlFlowIntensity | string | "normal" | none / light / normal / aggressive — roughly 0 / 25 / 60 / 100 % of eligible methods when no explicit include list is given. aggressive is Enterprise. |
controlFlowInclude | string[] | [] | Allowlist of methods to flatten, by Namespace.Type.Method. When non-empty, only these are transformed. Discover names with nebula inspect --methods. |
controlFlowExclude | string[] | [] | Methods to skip, by Namespace.Type.Method. |
obfuscateConstants | bool | false | Replace integer literal loads with an equivalent XOR expression decoded inline at runtime. |
encryptMethods | bool | false | Strongest code protection: encrypt a method’s whole IL and re-emit it at call time via the Nebula.Runtime helper (copied next to the output). Covers static, non-generic methods without exception handlers or by-ref/pointer parameters. |
encryptResources | bool | false | Encrypt embedded resources read via Assembly.GetManifestResourceStream(string) and decrypt on demand. (.resources for ResourceManager/WinForms/satellite are skipped.) |
Anti-tamper & anti-debug
| Key | Type | Default | Description |
|---|
antiTamper | bool | false | Inject a load-time integrity check (SHA-256 of the written image) that reacts if the file was modified after obfuscation. Stops casual patching. |
antiTamperReaction | string | "terminate" | On mismatch: terminate (FailFast), throw, exit, or callback. |
antiTamperCallback | string | null | Namespace.Type.Method of a static, parameterless method to call when reaction is callback (must be preserved so it resolves). |
antiDebug | bool | false | Inject a managed-debugger detection check that runs on module load. Off by default so it never hinders your own QA builds. |
antiDebugReaction | string | "throw" | On a detected debugger: throw, terminate, exit, or callback. |
antiDebugCallback | string | null | Callback method for the anti-debug callback reaction. |
| Key | Type | Default | Description |
|---|
metadataHardening | bool | false | Strip compile-time-only metadata decompilers use but the CLR doesn’t need (nullable annotation attributes, etc.), preserving runtime-critical metadata. |
pdbMode | string | "none" | none discards debug symbols (max protection); obfuscated emits a PDB matching the obfuscated IL for your private crash analysis. |
Signing
| Key | Type | Default | Description |
|---|
strongNameKeyFile | string | null | Path to a .snk to re-sign the output (renaming invalidates any existing strong name). Relative paths resolve against the config file. |
strongNameKeyEnvVar | string | null | Name of an env var holding a base64-encoded .snk, so keys need not live in the config. Takes precedence over strongNameKeyFile. |
delaySign | bool | false | Delay-sign only (embed the public key, leave room for a later signature). |
authenticodeCertFile | string | null | .pfx to Authenticode-sign the output (after strong-name signing). Requires signtool / Windows SDK. |
authenticodeCertPassword | string | null | Password for the .pfx — prefer supplying via an env var over inline text. |
authenticodeCertThumbprint | string | null | SHA-1 thumbprint of a cert in the Windows store to sign with (alternative to a .pfx). |
authenticodeTimestampUrl | string | null | Optional RFC-3161 timestamp URL for Authenticode signing. |
Licensing, incremental & extensibility
| Key | Type | Default | Description |
|---|
licenseFile | string | null | Path to a license file. When omitted, the NEBULA_LICENSE env var and default locations are checked. Without a valid license, the Free edition runs. |
seedMapFile | string | null | A previous run’s .symbols.json for incremental/seeded obfuscation: unchanged members reuse their previous obfuscated names; only added/changed members get new names. |
plugins | string[] | [] | Paths to plugin assemblies providing extra IObfuscationPass implementations. Each is appended to the pipeline. |
watermark | string | null | Enterprise. A per-customer identifier embedded (obfuscated) into the output so a leaked binary traces back to the customer. Read it with nebula watermark --read. |
A fuller example
{
"inputs": ["out/MyApp.dll", "out/MyApp.Core.dll"],
"outputDirectory": "out/obf",
"preservePublicApi": false,
"crossAssemblyRename": true,
"encryptStrings": true,
"controlFlowObfuscation": true,
"controlFlowIntensity": "normal",
"obfuscateConstants": true,
"antiTamper": true,
"metadataHardening": true,
"strongNameKeyEnvVar": "MYAPP_SNK_BASE64",
"pdbMode": "none"
}
See also: CLI reference · MSBuild & CI ·
Multiple assemblies.