Static or dynamic analysis: which one should review your FiveM resources?
In short
Static analysis reads a FiveM resource without running it; dynamic analysis executes it in a sandbox and watches what it does. For pre-installation review of FiveM resources, static analysis is the right default: nothing malicious executes during the check, the whole resource is examined rather than only the paths that happened to run, and the result points at specific files and lines the operator can verify. Dynamic analysis sees through obfuscation and runtime-constructed code, which static analysis cannot always resolve, but it only observes the behaviour that occurred during the run — and modern payloads routinely delay, check for sandboxes, or require a real player to trigger. In practice the two are complementary, and the honest position is to state clearly which questions each one can and cannot answer.
Key takeaways
- Static analysis never executes the sample — the review itself cannot compromise anything.
- Static analysis covers all code paths; dynamic analysis covers only the ones that ran.
- Dynamic analysis defeats obfuscation, which is exactly where static analysis is weakest.
- Evasion is cheap: a sleep, a sandbox check, or a trigger that needs a real player defeats naive dynamic runs.
- Whichever you use, the output must be evidence you can verify — not a score you have to trust.
Every code-security tool sits somewhere on one axis: does it reason about the program, or does it watch the program? Both answers are legitimate, they fail in opposite ways, and picking one is an engineering decision with consequences the user should be able to see.
The two approaches, precisely
Static analysis parses the source into a syntax tree and reasons over it: which functions exist, which values reach which calls, what the manifest loads. Nothing runs. Dynamic analysis puts the resource into an instrumented environment, starts it, and records syscalls, network connections and file writes. Everything runs.
| Property | Static | Dynamic |
|---|---|---|
| Executes the sample | No | Yes |
| Code coverage | All reachable code | Only paths that ran |
| Handles obfuscation | Partially — structure yes, values often no | Yes, by observing the result |
| Handles delayed / triggered payloads | Yes — the code is there to read | Only if the trigger fires during the run |
| Evidence produced | File, line, data-flow path | Observed behaviour, timestamps, endpoints |
| Cost per scan | Low, seconds | High, sandbox per sample |
| Risk to the analysis host | None | Real, requires isolation |
Why FXScan is static
The decision follows from the use case. Operators scan a resource before installing it, often one they just paid for, and they need an answer in seconds, not a sandbox session. Three properties made static analysis the obvious fit.
- 1
The review must be safe by construction
A pre-install check that runs the code has to be sandboxed perfectly every time. A check that never executes anything cannot be escaped, because there is nothing to escape from.
- 2
Coverage matters more than fidelity here
The characteristic FiveM backdoor waits for something — a specific player, a delay, a command. A dynamic run of thirty seconds sees none of that. Reading the file sees all of it.
- 3
The output has to be verifiable by a non-specialist
'server/main.lua line 214 takes the body of an HTTP response, decodes it at line 218, and passes it to load() at line 221' is something a server owner can open and check. A behavioural trace is not.
Where static analysis genuinely fails
Being clear about limits is not modesty, it is the only way a result means anything.
- Runtime-constructed code. If a string is assembled from arithmetic across several files, constant folding may not resolve it. The structural signal remains — something is building a string and executing it — but the payload does not.
- Escrow-encrypted resources. There is no source to read. The correct output is 'not analysable', not 'clean'.
- Remote content. A resource that downloads code is flagged as a loader, but what the endpoint returns tomorrow is unknowable today.
- Intent. Static analysis finds that data flows from the network into execution. Whether the author meant it as a plugin system or a backdoor is a human judgement.
Where dynamic analysis genuinely fails
- Coverage. Only what ran was observed. A payload triggered by an admin command on day forty simply does not appear.
- Evasion. Sandbox detection, timing checks and 'only fire for a real licence identifier' are cheap to write and common in practice.
- Reproducibility. A remote endpoint can serve benign content to your sandbox and a payload to real servers. Same sample, different verdict, no way to tell from the run.
- Cost and safety. Every sample needs an isolated environment, network egress control, and teardown. That is real infrastructure, not a library.
What a combined approach looks like
The mature answer is layering, and it is where our work is heading: static analysis as the fast, safe, universal first pass; targeted dynamic confirmation for the narrow set of samples where static analysis identifies a loader but cannot resolve the payload; and continuous re-checking so that a verdict is attached to a version rather than to a resource forever.
That last part matters more than the static-versus-dynamic argument. Both approaches produce a statement about one version of one archive at one moment. A server runs for months. The re-check is what keeps the statement true, which is why Titan Security Cloud is built around monitoring change rather than around a single verdict.
Try the static analysis pipelineArchive validation, safe extraction, manifest discovery, AST and taint analysis, evidence generation — nothing in the archive is ever executed.Frequently asked questions
What is the difference between static and dynamic analysis for FiveM resources?
Static analysis parses the resource's source code and reasons about it without running anything, so it covers every code path and cannot be harmed by the sample. Dynamic analysis executes the resource in an isolated sandbox and records what it actually does, which sees through obfuscation but only observes the behaviour that occurred during that particular run.
Why does FXScan not run the resource it analyses?
Because the review happens before installation and must be safe by construction. A check that never executes code cannot be escaped by a malicious sample, and it covers paths that a short sandbox run would never trigger — which matters because FiveM backdoors typically wait for a specific player, command or delay before doing anything.
Can static analysis detect obfuscated FiveM backdoors?
Partially. Structural facts survive obfuscation — a network call and a dynamic load are still visible — but the values flowing between them are often assembled at runtime specifically so they cannot be resolved statically. The right response is to report the structural risk and say clearly that the payload could not be resolved, rather than returning a clean verdict.