Reading fxmanifest.lua like a security reviewer

Published 6 min readTitan Software z.s.

In short

fxmanifest.lua is the single most useful file in a FiveM resource for a security reviewer, because it declares what the runtime actually loads and where each file runs. server_scripts run inside your server process with database credentials and console access; client_scripts run on players' machines and can be tampered with but cannot reach your data; shared_scripts run in both, which doubles the surface; and files simply exposes content to clients. Directives worth stopping on include wildcard globs that hide new files from review, paths escaping the resource directory, dependency and provider declarations that pull in code you did not audit, and any manifest whose declared entry points do not match what the archive actually contains. Reading the manifest first turns a 200-file archive into a short list.

Key takeaways

  • server_scripts is the highest-value section: that code runs with your credentials.
  • Wildcard globs hide future files from a review that only read the manifest.
  • shared_scripts doubles the surface — the same file gains both client reach and server privilege.
  • A file present in the archive but absent from the manifest is not automatically harmless; it may be loaded another way.
  • Mismatch between what the manifest declares and what the archive contains is itself a finding.

Every FiveM resource has to declare itself. That declaration is fxmanifest.lua, and it is the closest thing the ecosystem has to a manifest of permissions: which files exist as far as the runtime is concerned, which side each one runs on, and what the resource depends on. For a reviewer, it is where the work starts.

The directives that decide the blast radius

DirectiveRuns whereCan reach
server_scriptsYour server processDatabase, convars, console, filesystem, outbound network, ACE grants
client_scriptsEvery connected player's gameGame state, the player's own session, outbound network from the client
shared_scriptsBoth sidesEverything in both rows above — reviewed twice, not once
filesSent to clients on demandNothing by itself, but this is how NUI assets and data reach the client
ui_pageClient NUI browserThe HTML/JS bundle, which is real code and deserves its own review
dependencies / provideResolution order and identityPulls other resources into play, or claims to be one
What each loading directive actually grants

The practical consequence: if you can only read one section, read server_scripts. A backdoor in a client script is a nuisance and a cheating vector. A backdoor in a server script is your database.

A manifest that should not worry you

lua
fx_version 'cerulean'
game 'gta5'
author 'Example Studios'
version '2.4.1'

shared_scripts { 'config.lua' }
client_scripts { 'client/main.lua', 'client/nui.lua' }
server_scripts {
  '@oxmysql/lib/MySQL.lua',
  'server/main.lua',
  'server/commands.lua',
}

files { 'html/index.html', 'html/style.css', 'html/app.js' }
ui_page 'html/index.html'

dependencies { 'oxmysql' }
Explicit, minimal, everything named

Everything is named individually. The reviewer's list is five Lua files and one HTML bundle. If a sixth Lua file appears in the archive, it is not loaded — which is interesting in itself, but not dangerous by this route.

Red flags, in order of how often they matter

1. Wildcard globs in loading directives

lua
server_scripts { 'server/**/*.lua' }

Convenient for developers, hostile to review. Any file dropped into that tree in a future update loads automatically, and a reviewer who checked the manifest last month has no signal that the file set changed. Not malicious, but it means the manifest is no longer a reliable inventory — enumerate the directory yourself.

2. Paths that leave the resource

Entries containing ../ or absolute paths are trying to load code from outside the resource directory. There is very little legitimate reason for this in a distributed resource, and it defeats every assumption a per-resource review makes.

3. Unexpected shared_scripts

A file in shared_scripts runs on both sides. Config files legitimately live there. A file called something like utils.lua or core.lua in shared_scripts, containing network logic, deserves a full read — it has client reach and server privilege at the same time.

4. Identity claims and dependency injection

provide 'somecore' tells the runtime this resource satisfies another resource's name. In a framework ecosystem where resources look each other up by name, that is a way to insert yourself into a call path other code trusts. Check that any provide or dependencies entry matches what the resource is honestly for.

5. Manifest and archive disagree

Compare the declared file list against the archive contents in both directions. Files declared but missing suggest a partial or tampered archive. Files present but undeclared may be dead weight, may be loaded dynamically from Lua, or may be there for the operator to run manually — which is its own category of risk when the file is an .exe.

A five-minute manifest routine

  1. 1Open fxmanifest.lua and write down every server-side entry.
  2. 2Expand any glob by listing the directory it covers, and add those files to the list.
  3. 3Flag anything with ../, an absolute path, or a name that mimics a framework file.
  4. 4Note dependencies and provide entries, and check whether they are plausible for the resource's purpose.
  5. 5Diff declared files against archive contents; investigate anything on only one side.
  6. 6Read the server-side list. Then read the shared list. Then, if time allows, the client list.

This is exactly the step FXScan performs before any pattern matching: parse the manifest, resolve globs, build the real file graph, and label every file with the side it runs on. It is why the same suspicious pattern can be reported as critical in one file and informational in another — because context is what makes a finding actionable rather than noisy.

Let the manifest analysis run for youFXScan parses fxmanifest.lua declaratively and ranks every finding by whether the code actually runs, and on which side.

Frequently asked questions

What is fxmanifest.lua and why does it matter for security?

fxmanifest.lua is the declaration file every FiveM resource must include. It tells the runtime which files to load and whether each one runs on the server, on clients, or both. For a security reviewer it is the map: it turns an archive of hundreds of files into a short list of code that actually executes, and it identifies which of that code runs with your database credentials.

Are wildcard globs in fxmanifest.lua dangerous?

Not malicious in themselves, but they undermine review. An entry like server_scripts { 'server/**/*.lua' } loads any file added to that directory in a future update, so a reviewer who read the manifest cannot tell that the file set changed. If you see a glob, enumerate the directory yourself and treat the resulting list as the real manifest.

Should I worry about files in a resource that the manifest never loads?

They cannot execute through the normal loading path, so they are lower priority than declared server scripts. They are still worth a glance: an undeclared file may be loaded dynamically from Lua, may be an installer the operator is expected to run manually, or may be an executable that has no business in a Lua resource at all.

Related projects

Read next