vodka / Engine changelog
The engine, version by version. Every change, dated.
A plain, versioned record of what shipped in the vodka protection engine. Each release lists the changes that affect how your code is protected, stated factually and in step with the benchmarks.
0.2.2 · October 2026
Selective virtualization.
Maximum protection now keeps hot or looping code native and virtualizes only cold functions, so it stays near-native on typical code, with new per-function directives to override the choice.
- Selective virtualization. Maximum protection now virtualizes only cold functions and keeps hot or looping code native, so it is near-native on typical code instead of paying the per-function VM cost everywhere. New per-function directives: --@protect to force the VM onto a function, --@novm / --!native to keep one native.
0.2.1 · October 2026
Hardening, and a near-native default.
This release closed two static-analysis shortcuts, added an opt-in anti-tamper check and a minification-surviving leak-tracing fingerprint, and made the default pipeline near-native with the stronger virtual machine moved behind an opt-in toggle.
- Protection is near-native by default. The default pipeline is now a pure source rewrite (scope-aware renaming, encoded strings and numbers, control-flow flattening, watermark), so a protected script runs within noise of the original. The per-function bytecode VM moved to an opt-in Maximum protection mode.
- VM operator handlers are table-indirected. Under Maximum protection the virtual machine's operator handlers are dispatched through a table rather than written as readable one-line cases, so the interpreter no longer reads as a plain list of operations.
- The string-decode key is derived at runtime. Encoded string constants no longer ship their decode key in plaintext beside the ciphertext. The key is reconstructed at load time, which closes static recovery of the constants by reading the file.
- Opt-in bytecode self-integrity anti-tamper. Maximum protection can give the virtualized bytecode a self-integrity check, so editing its own code breaks the chunk instead of running tampered.
- Per-key leak-tracing fingerprint that survives minification. Each keyed delivery carries a traceable fingerprint that maps a casually re-shared copy back to the key that received it, and it now survives minification and a StyLua beautify. No-key and premium deliveries are unstamped.
0.2.0 · October 2026
The initial luau-guard engine.
The first shipped protection engine: source-to-source transforms, an opt-in per-function bytecode VM, and a watermark, differential-tested against the real Luau runtime.
- Scope-aware renaming. Local and upvalue names are rewritten with scope awareness; globals, table fields, method names, string keys and type names are never renamed.
- Encoded string and number constants. Strings are byte-encoded, integers rewritten as reversible arithmetic and floats exact-rewritten, so literal values are not sitting in plaintext in the file.
- Control-flow flattening. Supported functions are rearranged into dispatch state-machines, so the logic is harder to read top to bottom.
- Per-function bytecode VM. Supported functions can be compiled to bytecode and interpreted by a generated per-function virtual machine; functions outside the supported set keep native execution so behavior is preserved.
- Watermark. Output is minified and carries a per-build watermark, which is a build identifier rather than a claim of tamper resistance.
- Differential-tested against real Luau. Every build is re-run against the real Luau runtime and compared on output and exit code; a function that cannot be transformed with certainty bails to native rather than risk miscompiling.
Keep exploring
Where to go next.
How the engine works
The near-native default pipeline, the opt-in Maximum protection mode and the honest limits, in one place.
Reproducible benchmarks
Run the exact harness yourself: protection resistance, runtime overhead and the weaknesses we do not hide.
Protection, layer by layer
What each transformation does to your code, and where client-side protection has limits.
Questions
A few things worth knowing.
01Does a new engine release change my published script?
No. Your published loadstring keeps serving the build you last published. A protection change applies the next time you build and publish, and the validated-release pipeline means a failed or stale build never replaces your working release. Test a new build in your environment before publishing it.
02Did hardening the engine change the honest limits?
No. Running the loader still derives the decode key and recovers the string pool in plaintext, and a constant-folder still reverses the integer arithmetic. The 0.2.1 changes raise the cost of static analysis and casual copying; they do not make a client a vault. Keep secrets and access decisions on the server. See the [benchmarks](/benchmarks) for exactly what the engine does and does not defeat.
03What does the leak-tracing fingerprint trace, and what beats it?
It traces lazy re-sharing: a casually leaked keyed copy maps back to the key that received it, and the mark now survives minification and a beautify. A determined attacker who re-obfuscates or rebuilds the chunk strips it, and two buyers who diff their copies can find and remove it. It traces casual re-sharing, not a determined leaker.
Keep building
Protect your next build.
Every release here changes the default pipeline or the opt-in Maximum mode. Bring your source and build on the current engine.