Skip to main content
Junk code increases apparent complexity and script size, forcing an analyst to distinguish real logic from noise. When scattered strategically, junk code makes every line suspect: a function call might be critical, or it might do absolutely nothing. This page covers every major junk insertion technique for Lua and Luau, with code you can copy and adapt.

Dead Code Blocks

The simplest junk insertion is wrapping code in conditions that are always false.

Basic if false Blocks

Opaque-False Predicates

Realistic-Looking Dead Code

Bogus Computations

Insert arithmetic and string operations whose results are discarded.

Discarded Arithmetic

Discarded String Operations

Discarded Table Operations

Scattering Bogus Computations

Decoy Functions

Define functions with important-sounding names that are never called.

Full Decoy Function Example

Redundant Assignments

Assign a variable multiple times before its first real use.

Multiple Reassignments

Assignment Through Intermediate Variables

Combined with Junk Operations

Inline Constant Expansion

Replace simple literals with equivalent expressions.

Numeric Literal Expansion

Boolean Literal Expansion

String Concatenation

Before/After Function Example

Fake Error Handlers

Wrap code in pcall or xpcall with junk error handlers.

Basic Fake Error Handler

Error Handler with Decoy Logic

Automating Junk Insertion

You can automate junk insertion with a simple Lua script that reads source code and randomly inserts junk statements.
Randomize junk placement and content using os.time() as a seed so each obfuscation run produces different junk. This prevents analysts from diffing two versions to isolate real changes.
Excessive junk inflates file size and load time. Keep junk below 30% of total line count for scripts that are downloaded at runtime. For server-side or embedded scripts where size is not a concern, you can be more aggressive.
Basic deobfuscators prune obvious dead code: if false then blocks are trivial to eliminate. Junk works best when combined with opaque predicates so the dead code path is not obviously dead. A static analyzer that cannot prove (math.huge < 0) is always false must conservatively keep the branch. Layer junk with control flow obfuscation for maximum resilience.