Server configuration audit
Five seconds after it starts, Bastrel reads a few server convars and reports the ones that weaken your protection. It only reads: it never changes your configuration and never sanctions anyone for it.
What is checked
Section titled “What is checked”| Code | Convar | Expected | Severity |
|---|---|---|---|
BAS-CV-001 |
onesync |
on |
critical |
BAS-CV-002 |
sv_entityLockdown |
relaxed, strict or full |
critical |
BAS-CV-003 |
sv_filterRequestControl |
at least convars.minFilterRequestControl (default 2) |
high |
BAS-CV-004 |
sv_scriptHookAllowed |
false (0 accepted; not set is false) |
critical |
BAS-CV-005 |
sv_pureLevel |
1 or 2 |
medium |
BAS-CV-006 |
sv_enableNetworkedSounds |
false |
medium |
BAS-CV-007 |
sv_enableNetworkedPhoneExplosions |
false (not set is false) |
medium |
BAS-CV-008 |
sv_endpointPrivacy |
true |
low |
BAS-CV-009 |
rcon_password |
empty (RCon off) or at least convars.rconMinLength characters (default 24) |
high |
BAS-CV-010 |
sv_enableNetworkedScriptEntityStates |
false |
medium |
BAS-CV-011 |
sv_stateBagStrictMode |
true (recommended; not set is false, so it is reported) |
low |
BAS-CV-012 |
sv_netEventReassemblyUnlimitedPendingEvents |
false (not set is false) |
medium |
A convar that is not set counts as different, except sv_scriptHookAllowed, sv_enableNetworkedPhoneExplosions and sv_netEventReassemblyUnlimitedPendingEvents (their default is already false) and rcon_password (empty means RCon is off). Boolean values may be written true/false, 1/0 or on/off; any other text counts as different. For sv_stateBagStrictMode and sv_netEventReassemblyUnlimitedPendingEvents, write true or false: another spelling is reported as unreadable.
BAS-CV-011 is a recommendation. By default, FiveM lets a player write their own state bags and those of the entities they own. With sv_stateBagStrictMode true only the server can write them. Strict mode breaks scripts that write state bags from the client: check yours before enabling it, or set stateBagStrictRecommended = false in the convars section to stop the report (the convar is then not read at all). To enable it, put setr sv_stateBagStrictMode true in server.cfg before the server starts; it requires server artifact 12739 or newer. Bastrel reads the value of the convar, not the mode the server actually applies. BAS-CV-012 appears when sv_netEventReassemblyUnlimitedPendingEvents is true: the number of reassembled network events waiting per client is then unlimited (memory risk) and sv_netEventReassemblyMaxPendingEvents is ignored. Both finding lines name the convar and the value read ((not set) when it has no value).
Bastrel does not start at all without OneSync (see the startup page), so BAS-CV-001 only shows up if that gate is bypassed.
The report
Section titled “The report”The console shows one line per finding, with the convar, the expected value and the value found:
[bastrel] Convar audit: 1 finding(s).[bastrel] BAS-CV-005 sv_pureLevel: expected 1 or 2, got 0Each finding is also written to the database (bastrel_detections, no player, server = 1) and sent to Discord when it is high or critical. The rcon_password value is never read into a finding, a log or the console: only its length.
The recommended values depend on your server (for example sv_entityLockdown and sv_filterRequestControl have to be validated with your framework and inventory). Change them in server.cfg, then restart.
Routing buckets
Section titled “Routing buckets”If you create routing buckets (instances), you can set their entity lockdown in config/modules.lua:
convars = { lockdownBuckets = { [1] = 'strict', [2] = 'relaxed' },}The modes are strict (no entity created by clients at all), relaxed (script-owned entities created by clients are blocked) and inactive. The setting is applied once, after the audit.
Settings
Section titled “Settings”config/modules.lua, convars: delayMs (wait before the audit, 5000), minFilterRequestControl, rconMinLength, stateBagStrictRecommended (true: report BAS-CV-011), lockdownBuckets. An invalid value never stops Bastrel: each invalid field uses its default and the valid ones are kept (a bad lockdownBuckets entry is skipped, the others still apply), with a warning.
Resource scan
Section titled “Resource scan”After the audit, Bastrel reads the files of the other started resources, read-only, and reports what looks dangerous. It names the resource, the file and the line, and never prints the text it found (a webhook URL is a secret). Nothing is modified or deleted: you decide.
| Code | What it looks for |
|---|---|
BAS-CV-101 |
Code downloaded and run with load or loadstring (typical backdoors) |
BAS-CV-102 |
PerformHttpRequest in a client or shared script |
BAS-CV-103 |
A Discord webhook URL in a file sent to players |
BAS-CV-104 |
A client script that replaces TriggerServerEvent or TriggerEvent |
BAS-CV-105 |
A resource whose name matches another anticheat (scan.otherAnticheats) |
BAS-CV-107 |
Not a scan: most calls to an event, from several different players, carry no client SDK data, so a resource whose client triggers that event probably lacks the SDK (sdk.md). The finding names the event and the resource that registered it (registeredBy), not the caller. At most once per event and window; it changes no detection and no score |
The signatures are Lua patterns in config/whitelists.lua (scan.signatures), editable. They are hints, not an analysis: expect false positives (a legitimate PerformHttpRequest in a shared script) and misses (obfuscated code).
What the scan cannot read, listed at the end of the report as “not scanned” with the reason:
- files declared with a pattern (
client/*.lua,**/*.lua): FiveM gives the pattern, not the list of files, and a file can only be read by its exact path (glob); - files under Asset Escrow, which are encrypted (
escrow); - files that cannot be read (
unreadable) or are over 1 MiB (toolarge,scan.maxFileBytes); fileentries that are not text files (audio, images, models): they are never loaded (notext; the text extensions arescan.textExtensions).
The report names the first ten paths not scanned per resource, so you know what to audit by hand. A file under escrow is still read when it is covered by the resource’s escrow_ignore.
The scan runs once, 5 seconds after Bastrel starts, on the resources that are started at that moment. A resource started later is read alone when it starts, only when you use honeypots (see honeypots.md), and only for the names of your traps: a resource started after the scan began is never read for signatures, otherAnticheats or BAS-CV-105; otherwise it is only read at the next restart. To keep the report readable, at most scan.maxFindingsPerFile (20) findings per file and scan.maxFindingsPerResource (50) per resource are listed; the report says when the rest is cut.
The findings written per pass (the convar audit and the scan are two passes) are capped by pipeline.maxFindingsPerPass in config/modules.lua: an integer from 1 to 10000, optional, 100 by default (an invalid value makes the whole pipeline section use the built-in defaults, with a warning). Findings of severity high and critical are always written, even past the cap; the cap only holds back the lower ones (medium, low). When some were left out, one findings.capped line at the end of the pass gives the number left out and, per BAS-CV-* code, how many of each. The console report still lists everything.
In scan.signatures, an invalid entry (or a pattern Lua cannot read) is dropped with a warning; the other signatures keep working.
No alert does not mean a resource is clean. The scan only covers readable files. Resources declared with patterns or protected by escrow remain for you (or their author) to audit, so prefer resources whose origin you know.