Skip to main content
Automated deobfuscators often execute your script in a sandboxed Lua VM and observe its behavior to reconstruct the original logic. Detecting these environments at runtime lets you disable obfuscated functionality, produce misleading output, or waste the attacker’s computational resources. This page covers library probing, behavioral anomaly detection, coroutine and metatable checks, known deobfuscator fingerprints, and safe response strategies.

Detecting Sandboxed Standard Libraries

Sandboxes frequently strip or stub out standard library functions to limit what obfuscated scripts can do. Probing for the presence and behavior of these functions reveals whether your code is running in a restricted environment.

Library Presence Checks

Check whether functions that are normally available in a full Lua VM are missing or non-functional:
A high missing count suggests a sandboxed or emulated environment. os.exit and io are particularly common targets for removal because they allow scripts to affect the host system.

Scoring Function

Convert the results into a suspicion score that you can threshold against:
If the score exceeds a threshold you define (for example, 50), treat the environment as suspicious.

Detecting Behavioral Anomalies

Even when libraries are present, sandboxes and emulators often behave differently from a real Lua VM. Detect these anomalies by probing deterministic behavior.

math.random Seed Anomalies

In a real Lua VM, math.random without an explicit seed uses a default seed derived from the system time. In some sandboxes, the RNG is seeded to a fixed value for reproducibility. Check whether the sequence matches an expected non-seeded pattern:

Time Anomalies

Sandboxes sometimes return a fixed or stepped time from os.time(). Check whether time advances between two calls separated by a busy-wait loop:
If os.time() does not advance, the environment may be emulated or time is being controlled.

Function Address Anomalies

In a real Lua VM, tostring of a function includes a process-specific address. In some emulated VMs, function addresses are always 0x0 or a fixed value:
A 0x0 address suggests the VM is not allocating real function objects.

Coroutine Behavior Checks

Some sandboxes implement coroutines incorrectly. A specific yield and resume pattern may produce wrong status values or fail to preserve values across yields.

Coroutine Canary Test

If any of these assertions fail, the coroutine implementation is non-standard.

Metatable Behavior Checks

Metamethods are complex to emulate correctly. A sandbox with a simplified object model may fail to invoke __index and __newindex under all circumstances.

Metatable Canary Test

If index_called or newindex_called is false, the sandbox does not implement metamethods faithfully.

Detecting Known Deobfuscators

Some deobfuscators leave fingerprints in the global environment or modify standard functions in recognizable ways.

Global Name Fingerprints

Check for global names that deobfuscators inject to mark or hook your code:

pcall Wrapper Detection

Deobfuscators often wrap your script in pcall to catch errors during analysis. You can detect this by raising an error and inspecting the stack depth:

Responding to Sandbox Detection

When you detect a sandbox, avoid crashing loudly. A sudden error tells the analyst exactly which check triggered and helps them patch it.

Misleading Output Pattern

If a sandbox is detected, return plausible but wrong results for the first several calls, then stop entirely:
This pattern misleads an analyst who is tracing outputs to reverse engineer your algorithm. The first ten results look almost correct, which delays discovery of the sandbox detection.
Sandbox detection is an arms race. A determined analyst can patch your detection checks, replace your is_sandbox_detected function, or run your script in a fully faithful VM. Use sandbox detection to slow down automated tools and raise the cost of analysis, not as a definitive protection layer.