-
Notifications
You must be signed in to change notification settings - Fork 0
Deep Review Findings
Claude adversarial-review log (source-cited). This page records findings from independent verification passes against the Chernarus source mission, cross-checking the SQF code atlas, Gameplay systems atlas and other pages. Each finding is confirmed against
path:line, given a severity, and paired with a remediation playbook. It complements (does not replace) Codex's atlas pages and the Feature status register.
All paths are relative to the source mission root Missions/[55-2hc]warfarev2_073v48co.chernarus/. Arma 2 OA 1.64 — not Arma 3.
Read this page as an evidence ledger. For day-to-day work, start from the owner page below and use the DR entry only when you need the original source proof or fix shape.
| Finding family | DRs | Current canonical route | Status |
|---|---|---|---|
| PVF, direct-PV and network-data compile trust boundaries | DR-1, DR-27, DR-30, DR-38, DR-41, DR-44, DR-46 | Networking/PV, Public variable channel index, PVF dispatch playbook, Server authority map, Hardening roadmap | DR-1/DR-38 dispatcher lookup is partial source-present on current stable; registered allowlist/logging, sender auth, direct-PV and SEND_MESSAGE work remain code-owner lanes. |
| Economy, construction, purchases, services and upgrade authority | DR-6, DR-14, DR-16, DR-22, DR-23, DR-28, DR-33 | Feature status, Construction/CoIn, Factory/purchase, Economy authority first cut, Gear/loadout/EASA | Source-backed; route fixes through owner playbooks and smoke packs. |
| Commander, HQ and victory correctness | DR-11, DR-12, DR-13, DR-15, DR-20, DR-36, DR-47 | Commander/HQ lifecycle, Commander vote/reassignment, Victory/endgame, Pending owner decisions | Source-backed; DR-47 is source-unpatched and separate from DR-15. |
| Generated mission drift, modded stubs and release propagation | DR-2, DR-4, DR-32, DR-43 | Tools/build, Content/maps, Source fix propagation queue, Tooling release readiness audit | Source Chernarus and maintained Vanilla Takistan are the release focus; modded missions are non-authoritative unless regenerated. |
| Respawn, MASH, markers, WASP and partial/dead features | DR-3, DR-24, DR-25, DR-34, DR-35, DR-40 | Feature status, Respawn/death, WASP overlay, Abandoned feature revival, UI IDD collision repair | Keep source evidence; do not expand duplicate archaeology pages. |
| Headless, JIP, lifecycle and performance review cells | DR-5, DR-18, DR-19, DR-21, DR-37, DR-39, DR-42, DR-45 | AI/headless/performance, Headless delegation/failover, Lifecycle wait-chain, Performance opportunity sweep, Town AI vehicle despawn safety | Mixed source-backed bugs, clean reviews and smoke-pending propagated fixes. |
| External integrations, AntiStack, DiscordBot, Extension and governance | DR-7, DR-8, DR-9, DR-10, DR-26, DR-29, DR-31 | External integrations, Integration trust boundary audit, AntiStack DB extension audit, Community & Dev | Source-backed; secrets/config/runtime deployment choices remain owner decisions. |
| External report intake and clean-review records | DR-17, DR-26, DR-35, DR-36, DR-37, DR-38, DR-39, DR-40, DR-43 | External research reports, Codebase coverage ledger, Wiki pruning ledger | Keep as provenance and false-positive guards; avoid copying them into new pages. |
Current status 2026-06-21: the raw Call Compile evidence below is historical for current stable origin/master@0139a346. Source Chernarus now uses missionNamespace getVariable _script plus typeName == "CODE" guards at Server_HandlePVF.sqf:14-15 and Client_HandlePVF.sqf:32-33 via 7d60b02b4, and maintained Vanilla Takistan has the same lines via 9b49883cb. The dispatcher still lacks an explicit registered-handler allowlist and rejection logs, and DR-55 sender authentication plus direct-PV channels remain open. See PVF dispatch playbook for current branch status.
What. The PVF dispatch executes a string taken directly from the value a remote machine broadcast, with no validation that it names a known command.
-
Server/Functions/Server_HandlePVF.sqf:_script = _publicVar select 0; _parameters Spawn (Call Compile _script); -
Client/Functions/Client_HandlePVF.sqf: same pattern on_publicVar select 1. - The handlers are bound in
Common/Init/Init_PublicVariables.sqfasWFBE_PVF_<Command> addPublicVariableEventHandler { (_this select 1) Spawn WFBE_SE_FNC_HandlePVF }._this select 1is the new value chosen by the sender. - Clients legitimately reach the server channel via
Common/Functions/Common_SendToServerOptimized.sqf:15→publicVariableServer 'WFBE_PVF_<cmd>'.
The legitimate flow always sets index 0 to the bare identifier "SRVFNC<Command>", so Call Compile resolves a function-variable lookup. But nothing constrains the value to that shape: a crafted broadcast on a registered WFBE_PVF_* channel whose select 0 is arbitrary SQF text would be compiled and run on the receiver. This is the well-known Arma 2 publicVariable trust-boundary problem.
Why the usual mitigations are absent here.
-
No server-side validation.
Server_HandlePVF.sqfdoes not check that_scriptbegins withSRVFNCor is in the registered command set (confirmed: noSRVFNC/CLTFNCguard in either handler). -
No BattlEye filtering.
BattlEyeFilter/publicvariable.txtcontains a single rule,5 "kickAFK". That rule is the AFK-kick feature (the mission cannot kick directly, so it broadcastskickAFKand relies on BattlEye to kick the sender — see Networking and public variables). It is not a security filter: there is no restrictive default line and no whitelist of theWFBE_PVF_*channels with value constraints.
Severity rationale. This is a live-server hardening gap, not a mission-logic bug. It matters for any publicly-listed server (the README advertises one). It is recorded here as defensive guidance for the server owner.
Remediation playbook (cheapest first):
-
Validate before compile (server-side, no BE knowledge needed). In
Server_HandlePVF.sqf, reject any_scriptnot in the known set, e.g. build a lookup of"SRVFNC"+cmdfor every registered command at init andexitWith(with aWARNINGlog) if_scriptis not a member. Same idea forClient_HandlePVF.sqfagainstCLTFNC*. This neutralizes arbitrary-string compilation while preserving all legitimate traffic. -
Add a real BattlEye
publicvariable.txtas defense-in-depth: a restrictive default plus an explicit allow-list ofWFBE_PVF_*, the direct channels in the SQF code atlas "Direct Public Variable Channels" table, and the existingkickAFKrule. Do not add a blanket restrictive default without the allow-list, or you will break all PVF traffic. - Prefer
publicVariableClient/publicVariableServer(targeted) over broadcast for owner-directed messages to shrink the surface (already mostly done).
DR-2 — Paratrooper drop map markers were dead before source/Vanilla propagation — Superseded / smoke pending
Current status: this raw finding is historical for the maintained source path. Source Chernarus and maintained Vanilla Takistan now register HandleParatrooperMarkerCreation, compile the client handler and ship the sender/handler pair; see Paratrooper marker revival. Arma 2 OA smoke is still pending, and modded eden/Napf/lingor still register/send the callback without shipping Client/PVFunctions/HandleParatrooperMarkerCreation.sqf.
Server/Support/Support_Paratroopers.sqf:117 sends the marker:
[leader _playerTeam, "HandleParatrooperMarkerCreation", [_x, _sideID]] Call WFBE_CO_FNC_SendToClient;Common/Functions/Common_SendToClient.sqf turns that into WFBE_PVF_HandleParatrooperMarkerCreation (dedicated path) / CLTFNCHandleParatrooperMarkerCreation (hosted path). But:
- At the time of DR-2,
HandleParatrooperMarkerCreationwas not in the_clientCommandPVlist inCommon/Init/Init_PublicVariables.sqf, soWFBE_PVF_HandleParatrooperMarkerCreationhad noaddPublicVariableEventHandler, andCLTFNCHandleParatrooperMarkerCreationwas never compiled.
Historical result: on a dedicated server the marker PV was broadcast but never handled; on a hosted/SP server Spawn (Call Compile "CLTFNCHandleParatrooperMarkerCreation") resolved to nil. The fix has now been applied in source Chernarus and maintained Vanilla Takistan by adding HandleParatrooperMarkerCreation to _clientCommandPV. Remaining gates are Arma smoke and modded mission maintenance policy.
The intended MASH marker design is a two-hop relay:
- Client deploys tent →
WFBE_CL_MASH_MARKER_CREATED→ server EH inServer/Module/MASH/MASHMarker.sqf:1-13re-broadcastsWFBE_SE_MASH_MARKER_SENT. - The client EH that should consume
WFBE_SE_MASH_MARKER_SENTlives inClient/Module/MASH/receiverMASHmarker.sqf:1-29— but its only source/Vanilla reference is the commented compile atClient/Init/Init_Client.sqf:132://WFBE_CL_FNC_ReceiverMASHmarker = Call Compile preprocessFileLineNumbers "Client\Module\MASH\receiverMASHmarker.sqf";
2026-06-04 recheck: current source Chernarus and maintained Vanilla Takistan are even more inert than the original receive-side framing. Client/Module/Skill/Skill_Officer.sqf:25-27 creates and stores the MASH object and adds undeploy, but does not broadcast WFBE_CL_MASH_MARKER_CREATED; Client/Module/Skill/Actions/Officer_Undeploy_MASH.sqf:19-21 deletes the object and resets cooldown without marker cleanup. The server relay is active, but has no source/Vanilla sender. Modded eden and lingor still emit WFBE_CL_MASH_MARKER_CREATED, which is useful archaeology, but that is sender-only drift rather than proof the maintained missions have working shared MASH markers.
Result: on old-shape maintained roots, deployed MASH tents can still be local respawn objects, but shared MASH map markers are orphaned: no live sender, no compiled receiver, no server-held marker list and no explicit JIP resend/pull. Current stable/B69-shaped roots remove the maintained-root deploy/module path instead; use Respawn and death lifecycle for the current branch matrix. Fix: either restore the feature as a server-authoritative marker registry with explicit JIP resend and unique marker names, or remove/comment the relay and receiver as dead code.
DR-4 — Generated-mission drift: Takistan is in sync; the skip-list is a silent-divergence trap; modded maps are abandoned (generated-mission drift) — Medium
A full recursive diff of Missions/[55-2hc]…chernarus vs Missions_Vanilla/[61-2hc]…takistan shows every difference is exactly a LoadoutManager skip-listed file or blacklisted directory — there is no accidental drift between the two at this commit:
- Differing files:
mission.sqm,version.sqf(git-ignored),Client/GUI/GUI_Menu_Help.sqf,WASP/unsort/StartVeh.sqf,loadScreen.jpg,texHeaders.bin,Server/Init/Init_Server.sqf(theSET_MAP 1→2patch), and the blacklistedCommon/Config/Core_Artillery/*+Server/Config/*+Textures/*.
This is more reassuring but also more dangerous than the "generated missions can drift" framing elsewhere. The precise hazard is the skip-list, defined in Tools/LoadoutManager FileManagement/FileManager.cs (ShouldSkipFile + the co.takistan directory blacklist):
A gameplay edit made in Chernarus to any skip-listed file —
mission.sqm,GUI_Menu_Help.sqf,StartVeh.sqf, anything underCore_Artillery/,Server/Config/, orTextures/— will never propagate to Takistan viadotnet run. These must be hand-mirrored in both missions.
So the standard guidance "edit Chernarus + run LoadoutManager" is incomplete: it is correct for the ~95% of files that are copied, and silently wrong for the skip-listed set. See the expanded propagation guidance in Tools and build workflow.
Modded maps are abandoned/stale. Because modded propagation is commented out at Tools/LoadoutManager SqfFileGenerators/SqfFileGenerator.cs:132, the Modded_Missions/* trees are far behind Chernarus (787 files):
| Modded mission | File count | State |
|---|---|---|
…Napf |
507 | ~280 files behind |
…eden |
502 | ~285 behind |
…lingor |
438 | ~349 behind |
…dingor |
20 | stub |
…smd_sahrani_a2 |
4 | stub |
…tavi |
3 | stub |
…isladuala |
1 | stub |
None are deployable as-is; they would need full regeneration after the modded path is re-enabled. Treat Modded_Missions/* as non-authoritative.
The SQF code atlas states "659 preprocessFile references (452 preprocessFileLineNumbers + 207 plain)". An independent recount on the docs/developer-wiki-index base yields 678 total / 465 preprocessFileLineNumbers / 213 plain. The gap is small and likely reflects counting method (comment handling) or branch timing — not an error — but hardcoded counts rot as the mission changes. Recommendation: present such counts as point-in-time and ship the regeneration command so future agents verify rather than trust, e.g. (PowerShell, from the mission root):
(Get-ChildItem -Recurse -Filter *.sqf | Select-String -SimpleMatch 'preprocessFileLineNumbers').CountVerified-accurate cross-checks (for trust calibration): the atlas's FSM inventory is correct — exactly three .fsm files exist (Client/FSM/updateactions.fsm, Client/FSM/updateavailableactions.fsm, Client/kb/hq.fsm). AttackWave and LogGameEnd remain outside the standard PVF list; HandleParatrooperMarkerCreation was later moved into the client PVF list as a small revived feature.
- DR-2 is source/Vanilla propagated; smoke and modded drift remain. Decide fix-vs-remove for DR-3 (MASH markers), which is still dead on the receive side.
- DR-1 server-side validation is a small, safe gameplay-code change (Chernarus
Server_HandlePVF.sqf) — gate behind review since it touches the network hot path. - Re-confirm DR-4 modded-map decision: regenerate or formally retire
Modded_Missions/*.
Lane pvf-hardening-review. This turns DR-1 into a concrete, behavior-preserving change set a code owner can apply to the Chernarus source. Every claim below was re-verified against source on this pass. Paths relative to Missions/[55-2hc]warfarev2_073v48co.chernarus/.
The dispatch targets are already-compiled global variables, created at registration in Common/Init/Init_PublicVariables.sqf:44,49:
Call Compile Format["CLTFNC%1 = compile preprocessFileLineNumbers 'Client\PVFunctions\%1.sqf'", _x]; // :44
Call Compile Format["SRVFNC%1 = compile preprocessFileLineNumbers 'Server\PVFunctions\%1.sqf'", _x]; // :49So SRVFNCRequestJoin, CLTFNCTownCaptured, … are missionNamespace variables holding code. The dispatch line Spawn (Call Compile _script) only compiles the string _script to perform a variable lookup. That means the same resolution can be done with getVariable, which treats _script purely as a name and cannot execute an arbitrary SQF string a client injected.
Replace the compile-the-string dispatch with a name lookup that defaults to a no-op.
Server/Functions/Server_HandlePVF.sqf (current _parameters Spawn (Call Compile _script);):
private ["_fn"];
_fn = missionNamespace getVariable _script; // resolve SRVFNC<cmd>; unknown -> nil
if (isNil "_fn") exitWith {
["WARNING", format ["Server_HandlePVF: rejected unknown PVF command '%1' from network", _script]] Call WFBE_CO_FNC_LogContent;
};
if (typeName _fn != "CODE") exitWith {
["WARNING", format ["Server_HandlePVF: rejected non-code PVF command '%1' from network", _script]] Call WFBE_CO_FNC_LogContent;
};
_parameters Spawn _fn;Client/Functions/Client_HandlePVF.sqf (current _parameters Spawn (Call Compile _script);): identical pattern resolving CLTFNC<cmd>.
Why this is safe and behavior-identical:
- Legitimate traffic sets
_scriptto exactly"SRVFNC"+cmd/"CLTFNC"+cmd(seeCommon/Functions/Common_SendToServerOptimized.sqf:15,Common/Functions/Common_SendToClient.sqf), which resolves to the compiled function — unchanged. - A hostile value such as
"hint 'x'; <server-side effect>"is not a defined variable, sogetVariableleaves_fnnil and exits with a WARNING. Nocompileever runs on attacker text. - Use OA-safe
isNilandtypeNameguards. Do not useisEqualTohere; it is an Arma 3-era command and will mislead OA patch authors.
At the end of Init_PublicVariables.sqf, snapshot the legal command set so the handler check is explicit rather than implicit:
WFBE_SE_PVF_ALLOWED = [];
WFBE_CL_PVF_ALLOWED = [];
{WFBE_SE_PVF_ALLOWED = WFBE_SE_PVF_ALLOWED + [Format ["SRVFNC%1", _x]]} forEach _serverCommandPV;
{WFBE_CL_PVF_ALLOWED = WFBE_CL_PVF_ALLOWED + [Format ["CLTFNC%1", _x]]} forEach _clientCommandPV;
publicVariable "WFBE_SE_PVF_ALLOWED"; // optional; or keep server-localThen guard with if !(_script in WFBE_SE_PVF_ALLOWED) exitWith { ...log... }; before resolving. Fix 1 already covers the same cases; use Fix 2 only if you want a named, auditable whitelist.
The shipped BattlEyeFilter/publicvariable.txt is a single line, 5 "kickAFK", which is the AFK-kick feature trigger, not a security filter (see Networking and public variables → Security). A hardened filter uses a restrictive default first line plus explicit allow exceptions:
5 "" // default: kick on any unlisted PV broadcast
!="^WFBE_PVF_[A-Za-z]+$" // allow the dispatch channels
!="^wfbe_supply_temp_(west|east)$" // allow the supply request channel
!="^(ATTACK_WAVE_INIT|CLIENT_INIT_READY|REQUEST_SUPPLY_VALUE|WFBE_CL_MASH_MARKER_CREATED|AFKthresholdExceededName|WFBE_C_PLAYER_OBJECT|WFBE_CLIENT_HAS_CONNECTED_AT_LAUNCH)$"
5 "kickAFK" // keep the AFK feature kick
⚠️ Validate the exact client→server channel list against the "Direct Public Variable Channels" table in the SQF code atlas before deploying — a too-strict default with a missing exception will kick legitimate players. BattlEye regex/escaping differs from SQF; test on a private server first. This complements, and does not replace, Fix 1 (BE filters the variable name, not the payload shape).
Fix 1 stops arbitrary code execution, but the PVF model still trusts client-sent commands and parameters. A malicious client can broadcast a legitimate command with chosen arguments — e.g. RequestChangeScore (Server/PVFunctions/RequestChangeScore.sqf sets a player's score directly from the payload) or RequestStructure — because the server handlers largely don't authenticate the sender against the payload. Closing that is a larger, per-handler effort (validate that owner/sender matches the acting player, clamp economy/score deltas, range-check structure requests). Treat this as a separate follow-up lane, not part of the dispatch fix. Documented here so the dispatch fix isn't mistaken for full PVF authorization.
- No registered handler under
Server/PVFunctions/orClient/PVFunctions, norServer_HandleSpecial.sqf/HandleSpecial.sqf/LocalizeMessage.sqf, callscompileon its parameters — so once the dispatch command name is resolved safely, there is no second-order injection on the PVF path. DR-46 correction: the directSEND_MESSAGEpublicVariable path is outside PVF and does compile network message text; hardening therefore has two network-data compile surfaces: PVF dispatch command strings (DR-1) andSEND_MESSAGEpayload text (DR-46). Other non-networkcall compilesites still compile files (Init_Coin.sqf, EASA/CM init) or local engine key-strings (coin_interface.sqf:774-777). - Handoff: this is a Chernarus-source gameplay change → after applying, run
Tools/LoadoutManagerdotnet runto propagate (noteServer_HandlePVF/Client_HandlePVFare not on the skip-list, so they propagate normally;BattlEyeFilter/lives outside the mission and is deployed with the server, not via LoadoutManager).
Lane construction-authority-review (extends Construction and CoIn systems atlas, whose "Authority Boundary" section flags this risk generically; this finding adds per-handler forgery proof + a validation design). This is the concrete realization of the command-forgery residual scoped in Round 3 (Fix 1 closes code execution, not command forgery).
DR-6 — Construction request handlers perform no sender/authority/resource validation — High (gameplay integrity)
All three construction PVF handlers derive trust from the client-supplied payload and never verify the requester. Source (verified this pass):
| Handler | Validation actually performed | Client-controlled inputs | Forgery impact |
|---|---|---|---|
Server/PVFunctions/RequestStructure.sqf |
Only: does _structureType exist in WFBE_<side>STRUCTURENAMES. |
_side (select 0), class, pos, dir — all from payload. |
Forge ["RequestStructure",[WEST,"US_WarfareBHeavyFactory_EP1",anyPos,dir]] → server ExecVMs the construction script and builds a free factory anywhere for any side. No commander check, no funds debit, no placement/base-area/hostile-town checks (those are client-only, atlas "Placement Rules"). |
Server/PVFunctions/RequestDefense.sqf |
Only: does _defenseType exist in WFBE_<side>DEFENSENAMES. |
_side, class, pos, dir, _manned — all from payload. |
Forge unlimited free defenses — incl. AI-manned static weapons and minefields (Sign_Danger) — anywhere for any side, bypassing the base-area avail budget (decremented only client-side in coin_interface.sqf:724-730). |
Server/PVFunctions/RequestMHQRepair.sqf |
None. Body is [_this] Spawn MHQRepair;. |
entire payload; MHQRepair.sqf:3 uses _side. |
MHQRepair rebuilds the side HQ from server state (GetSideHQ/GetCommanderTeam/position) with no dead-HQ check, no commander check, and none of the repair count/price gating that lives only client-side in Action_RepairMHQ.sqf. Forge ["RequestMHQRepair",[side]] → free, unlimited HQ respawn/repair; can also fire while the HQ is alive. |
-
_sideis taken from the payload, not derived from the sender. A client can act on any side's behalf. - The payloads don't even include the requesting player object, so the handlers cannot identify or authorize the sender as written.
-
Arma 2 OA
addPublicVariableEventHandlerprovides no sender identity —_thisis[varName, value]only (unlike Arma 3remoteExecutedOwner/REownership). So authority must be reconstructed: the payload must carry the player, and the server must validate that player's role/side/funds against server-side state. (This is also why DR-1's command-validation fix does not, by itself, stop forgery.)
Add the requesting player to each request and validate server-side before creating objects. Example for RequestStructure (mirror for RequestDefense; for RequestMHQRepair validate dead-HQ + commander + repair-count/price server-side):
// client (coin_interface / Action_*): include the player in the payload
["RequestStructure", [player, sideJoined, _class, _pos, _dir]] Call WFBE_CO_FNC_SendToServer;
// server RequestStructure.sqf (new guards, then existing logic):
_player = _this select 0; _side = _this select 1; _structureType = _this select 2; ...
if (isNull _player) exitWith {};
if (side _player != _side) exitWith {}; // can't build for another side
if (_player != leader ((_side) call WFBE_CO_FNC_GetCommanderTeam)) exitWith {}; // commander-only
private _cost = /* look up WFBE_<side>STRUCTURECOSTS[index] */;
if ((_side call WFBE_CO_FNC_GetSideSupply) < _cost) exitWith {}; // server-authoritative funds
[_side, -_cost, "structure build", false] call WFBE_CO_FNC_ChangeSideSupply; // debit on server
// ...then the existing class-exists lookup + ExecVM construction scriptNotes:
- Keep the client cost-deduction/preview for instant UX, but make the server the final authority on debit and creation (atlas "Cost deduction" risk row agrees). Avoid double-debit by having the client send a request and the server be the source of truth (or reconcile on the server-confirmed message).
- Re-checking full placement/collision server-side is heavier; at minimum validate side+commander+funds+class (cheap, closes the worst abuse). Base-area
availshould also be decremented/validated server-side to stop the unlimited-defense path (traceRequestBaseArea+Construction_StationaryDefensetogether, per the atlas, for JIP safety). - This is gameplay-code; gate behind review (touches the build hot path) and run LoadoutManager after.
RequestStructure/Defense/MHQRepair.sqfare not on the skip-list, so they propagate normally.
Not a crash/RCE (that's DR-1). This is gameplay-integrity / anti-grief: on a public server, a modified client can mint free factories/defenses/HQs and bypass the economy. Pair with DR-1 (validate the command) — DR-1 stops arbitrary code, DR-6 stops forged legitimate commands; both are needed for a hardened public server.
Lane antistack-db-trust. The AntiStack module persists per-player score/side and team skill to an external native extension for team-balancing. Source: Server/Module/AntiStack/callDatabase*.sqf (7 callExtension sites) + the A2WaspDatabase DLL, which is not in this repo (only the in-repo Extension/ GLOBALGAMESTATS DLL is — see External integrations). All claims verified this pass.
DR-7 — The server call compiles the extension's return value on every call — High (external trust boundary)
Every one of the seven handlers does, in effect:
_response = "A2WaspDatabase" callExtension format ["%1,%2", _procedureCode, _parameters];
_response = call compile _response; // <-- executes the DLL's stdout as SQF
_responseCode = _response select 0;(callDatabaseStore.sqf, callDatabaseRetrieve.sqf ×2 incl. the 505 poll, callDatabaseSendPlayerList.sqf, callDatabaseRequestSideTotalSkill.sqf ×2, callDatabaseSetMap.sqf, callDatabaseStoreSide.sqf, callDatabaseFlushPlayerList.sqf.)
callExtension returns a string from a native DLL, and the mission compiles+executes it. The server therefore fully trusts the A2WaspDatabase process's stdout as code. Why this matters:
- Compromise/replacement/bug → server RCE. Any DLL that returns SQF other than the expected numeric array literal runs on the server. The DLL is third-party and absent from the repo, so its behaviour can't be audited here.
-
Malformed/empty return → error cascade. If the DB is down/slow/encoding-broken,
callExtensionreturns""→call compile ""isnil→nil select 0throws. Several handlers only guardtypeName _responseCode == "SCALAR"after theselect 0, so the select can throw first. - Echo-to-code latent risk. Only UID/score/side/map round-trip today (all constrained, low risk). But the pattern means any future free-text field persisted and echoed back becomes executable.
Engine caveat (why the pattern exists): Arma 2 OA 1.64 has no parseSimpleArray (that is Arma 3), so call compile is the idiomatic string→array path for extensions. The A2-correct hardening is defensive validation, not a parser swap:
- Guard the raw string first with OA-safe checks:
if (isNil "_response") exitWith { /* neutral fallback + WARNING */ }; if (_response == "") exitWith { /* neutral fallback + WARNING */ }; - Compile, then shape-check before use:
_response = call compile _response; if (typeName _response != "ARRAY") exitWith {...}; if ({ typeName _x != "SCALAR" } count _response > 0) exitWith {...}; - Only then read
_response select 0/1/2. This keeps the DLL contract (numeric arrays) but refuses to execute anything that isn't one.
callDatabaseRetrieve.sqf polls the 505 procedure up to 120 × 0.10s ≈ 12s; callDatabaseRequestSideTotalSkill.sqf polls 707 up to 9 × 3s = 27s. These feed player-connect stat retrieval and team-skill balancing (called from mainLoop.sqf, getTeamScoreMonitor.sqf, Init_Server.sqf). They run in spawned scripts so the server tick survives, but a slow/down DB stalls join/balance up to those windows before falling back to neutral ([1,1] / 0). Recommend a shorter ceiling + a circuit-breaker that flips WFBE_C_ANTISTACK_ENABLED off after N consecutive timeouts.
callDatabaseSendPlayerList.sqf packs every player's guid,side pair into a single callExtension input string (g1,1,g2,2,…). Arma 2 OA callExtension has input/output length limits (output historically ~10 KB); a 55-slot roster can produce a long argument and an even longer response, risking truncation → call compile of a truncated array literal → parse error (compounding DR-7). Recommend chunking the player list across multiple calls and validating each response shape.
WFBE_C_ANTISTACK_ENABLED defaults to 1 (Init_CommonConstants.sqf:171), and the A2WaspDatabase DLL is an undocumented external runtime dependency absent from the repo. Any server/dev instance lacking the DLL gets callExtension→""→call compile→error per call unless the param is set to 0. Marty added per-call if (… == 0) exitWith disable guards (good), but the default is on. Recommend: document the external dependency in External integrations, and consider detecting DLL presence (a cheap PING procedure) to auto-disable rather than error.
Code owners: apply DR-7 defensive validation (guard empty + shape-check before reading) to all seven callDatabase*.sqf; add a circuit-breaker (DR-8); chunk SEND_PLAYERLIST (DR-9); document/auto-detect the external DLL (DR-10). Codex: the A2WaspDatabase external dependency + call compile trust contract should be called out in the External integrations page (its lane). Ledger: Integrations Auth/PV cells advanced from ⬜ to 🟡 (AntiStack covered; Extension/Discord/BattlEye still pending).
Lane victory-endgame-review. Source: Server/FSM/server_victory_threeway.sqf (the only script that sets gameOver/WFBE_GameOver/failMission — verified by grep across Server/), Server/Functions/Server_LogGameEnd.sqf, Server/PVFunctions/LogGameEnd.sqf, Common/Init/Init_CommonConstants.sqf:401.
DR-11 — Endgame reports the winner inconsistently; persisted win-tally is wrong for the all-towns win — Superseded / fixed in master (B67, wiki-wins)
The trigger merges a lose test and a win test into one condition and then handles both identically:
if (!(alive _hq) && _factories == 0 || _towns == _total && !WFBE_GameOver) then {
[nil,"HandleSpecial",["endgame",(_x) Call WFBE_CO_FNC_GetSideID]] Call WFBE_CO_FNC_SendToClients;
WF_Logic setVariable ["WF_Winner", _x];
gameOver = true; WFBE_GameOver = true;
_side = west; if (_x == west) then {_side = east};
[_side] call WFBE_CO_FNC_LogGameEnd; // Server_LogGameEnd: _this select 0 == WINNER
}SQF precedence (&& before ||) parses this as (!alive _hq && _factories==0) || (_towns==_total && !WFBE_GameOver):
-
Branch A —
_xHQ dead and no factories →_xis the loser.LogGameEnd(_side = opposite of _x)records the correct winner. ✓ -
Branch B —
_xholds all towns →_xis the winner. ButLogGameEndis still called with_side= opposite of _x → it records the loser as the winner in the persisted%1_WIN_CHERNARUSprofileNamespace tally. ✗
Consequences:
- The win/loss statistics saved via
WFBE_CO_FNC_LogGameEnd(→profileNamespace,saveProfileNamespace) are inverted for every all-towns victory. -
WF_Logic setVariable ["WF_Winner", _x]—WF_Winneris read byAI_Commander.sqf:593for round-end telemetry logging. The inverted-tally bug still means the wrong side may be logged in profileNamespace on the all-towns win path. - The
endgameclient broadcast sends_x's sideID toWFBE_CL_FNC_EndGame(HandleSpecial.sqf:16) for both opposite scenarios, so the player-facing outro shows the same side regardless of who actually won — at least one path is wrong. (Follow-up: confirm whether EndGame treats the payload sideID as winner or loser.) -
Guard/precedence bug:
!WFBE_GameOverguards only the towns branch, and theforEachover sides has no break after settinggameOver. Branch A is unguarded, so if two sides both satisfy "HQ dead + no factories" in the same 80s tick, endgame fires twice (doubleendgamebroadcast, doubleSET_MAP, doubleLogGameEnd). Fix: guard both branches with!WFBE_GameOver(orexitWithafter the first winner) and split the win/lose logic so the winner is computed correctly per branch.
WFBE_C_VICTORY_THREEWAY defaults to 0 (Init_CommonConstants.sqf:401, comment "0: Side a vs Side b [supremacy] minus defender"), and the detection block is gated if (!gameOver && _victory == 0). Since server_victory_threeway.sqf is the only victory/failMission setter in Server/, selecting any non-zero WFBE_C_VICTORY_THREEWAY value disables victory detection entirely — matches never auto-end in the mode the file is named for. Either implement the threeway path or document the parameter as non-functional.
-
Server/Functions/Server_LogGameEnd.sqf— clean; wired toWFBE_CO_FNC_LogGameEnd(compiled twice,Init_Server.sqf:64and:89). -
Server/PVFunctions/LogGameEnd.sqf— removed from master; was a buggy duplicate. OnlyServer/Functions/Server_LogGameEnd.sqfremains., and readsprofileNamespace getVariable WEST_WIN_CHERNARUS(bare global, not the"WEST_WIN_CHERNARUS"string). If this variant is ever wired in, win-stat persistence silently corrupts. Recommend deleting the duplicate to prevent future mis-wiring.
Code owners: fix DR-11 (split win/lose branches, compute winner per branch, guard both branches / break the loop) — this corrects permanently-skewed win stats; decide DR-12 (implement or document-as-disabled threeway); delete the buggy PVFunctions/LogGameEnd.sqf (DR-13). Follow-up review item: WFBE_CL_FNC_EndGame payload semantics (winner vs loser sideID). Ledger: Victory/endgame Map/Auth/PV/Perf cells advanced.
Lane factory-purchase-authority. Builds on Codex's Factory and purchase systems atlas (which noted player buy is client-local with no RequestBuyUnit PVF) and adversarially verifies Cicero's flagged Server_AssignNewCommander candidate. All claims verified at source.
DR-14 — Player unit purchasing has no server authority (the economy ceiling) — High (gameplay integrity), architectural
The player buy path never contacts the server:
-
Client/GUI/GUI_Menu_BuyUnits.sqf:102,108check funds client-side;:155-156do_params Spawn BuildUnit; -(_currentCost) Call ChangePlayerFunds;. -
Client/Functions/Client_BuildUnit.sqf:217/249/…create the unit/vehicle directly on the buyer viaWFBE_CO_FNC_CreateUnit/WFBE_CO_FNC_CreateVehicle(enginecreateUnit/createVehicle). There is noRequestBuyUnitPVF (confirmed: not inInit_PublicVariables.sqf, noServer/PVFunctions/RequestBuyUnit.sqf). - Funds live in
wfbe_fundson the team group, written byCommon_ChangeTeamFundswithsetVariable [..., true](broadcast, client-writable — see Round 1 / DR-6 root cause).
So a modified client can mint any factory unit for free (skip the deduction, or set wfbe_funds directly) — and the created vehicle is globally synced because client createVehicle in MP is global. This is the ceiling on the DR-1/DR-6 hardening thread: unlike construction (DR-6, which at least routes through a server PVF that could be validated), the player economy and unit production are architecturally client-authoritative in WFBE's locality model. Fully fixing it = a large redesign (route purchases through a validated server PVF like construction). The realistic live-server defense is a BattlEye script filter (scripts.txt) constraining client createVehicle/createUnit, not a publicVariable filter. Document this ceiling so future hardening targets the right layer.
Latent path note (confirms atlas):
Server_BuyUnit.sqf/AIBuyUnitis compiled (Init_Server.sqf) but has no proven dynamic caller — the AI-commander production path that would use it is itself dormant (the AI commander FSM never starts; see Cicero's server atlas + DR-15 neighbourhood).
Adversarial verification of Cicero's candidate — confirmed live by tracing compile + sole caller:
-
Init_Server.sqf:62:WFBE_SE_FNC_AssignForCommander = Compile … "Server\Functions\Server_AssignNewCommander.sqf". - Sole caller
Server/PVFunctions/RequestNewCommander.sqf:13:[_side, _assigned_commander] Spawn WFBE_SE_FNC_AssignForCommander;(a 2-element array). -
Server/Functions/Server_AssignNewCommander.sqf:3:_side = _this;— sets_sideto the whole array[side, commander](should be_this select 0), then_commander = _this select 1(correct)._logic = (_side) Call WFBE_CO_FNC_GetSideLogicthen receives an array, not a side → wrong/objNulllogic → the block that stops the AI-commander FSM (_logic getVariable "wfbe_aicom_running") operates on a bad logic and fails.
Impact: when a human is assigned commander via RequestNewCommander, the AI-commander shutdown path mis-fires (mitigated in practice because the AI-commander FSM is itself dormant — DR-14 note). There's also a redundant new-commander-assigned broadcast (sent by both RequestNewCommander.sqf and Server_AssignNewCommander.sqf). Fix: _side = _this select 0;. One-line change in Chernarus source.
RESOLVED on current
master(source-confirmed 2026-06-07, megapass). The primary call-shape bug is fixed:Server/Functions/Server_AssignNewCommander.sqf:4now reads_side = _this select 0;(with a Marty comment: "the direct commander assignment receives [side, commanderTeam]") and:5_commander = _this select 1;, soGetSideLogicgets a real side and the AI-com shutdown block operates on the correct logic. The minor secondary item is not fixed: thenew-commander-assignedbroadcast is still sent by bothRequestNewCommander.sqf:14andServer_AssignNewCommander.sqf:10(duplicate). DR-15's core defect is closed on master; only the redundant-broadcast cleanup remains (cosmetic). This is the one DR the resolved-issue sweep found genuinely fixed; DR-1..DR-14, DR-16..DR-57 remain open on master.
Code owners: (DR-14) decide whether to route player purchases through a validated server PVF (large) or accept client-authority + add a BattlEye scripts.txt filter; (DR-15) one-line fix _side = _this select 0 in Server_AssignNewCommander.sqf and drop the duplicate new-commander-assigned broadcast. Ledger: Factory/purchase Auth/PV advanced; AI-commander caveat cross-linked.
Lane ui-hud-authority-review. Cross-checks Codex/Curie's Client UI systems atlas and reviews the economy-menu sale authority (the DR-6/DR-14 sibling). Verified at source.
Client/GUI/GUI_Menu_Economy.sqf:104-152 (MenuAction 105, "Sell Building"):
- The commander check is client-side only (
_isCommanderviacommanderTeam == group player,:107-109). - It picks the closest own-side structure (
GetSideStructures,:110-112), then in a spawned thread credits the refund client-side —ChangeSideSupply(broadcast, client-writable) orChangePlayerFunds(:141) — and destroys the structure client-side with_closest setDammage 1(:152), which propagates globally because the structure is a synced object. - No server PVF, no server validation (same pattern as DR-6 construction and DR-14 purchasing). A modified client bypasses the commander gate and the
WFBE_SOLDre-sell guard, mints the refund, and demolishes structures. Same client-authority ceiling: the realistic defense is a BattlEyescripts.txtfilter constraining clientsetDammage/funds writes, or routing sell through a validated server PVF (matches the DR-6 fix shape). This completes the economy picture: build (DR-6), buy (DR-14), and sell (DR-16) are all client-authoritative.
DR-17 — Duplicate dialog IDD 23000 (EASA vs Economy) — Low-Medium (UI correctness) — confirms Curie candidate
Rsc/Dialogs.hpp: class RscMenu_EASA (:3209, idd = 23000 at :3211) and class RscMenu_Economy (:3287, idd = 23000 at :3289) share the same display id. findDisplay 23000 is therefore ambiguous, and any control-event/closeDialog/findDisplay 23000 logic can target the wrong dialog if both are reachable. Verified Curie's flagged candidate at source. Fix: give EASA and Economy distinct IDDs (and audit any findDisplay 23000 callers). Also re-confirmed Curie's note that other UI candidates (stale RscMenu_Upgrade → missing GUI_Menu_Upgrade.sqf; suspect RscClickableText.soundPush[]) remain open for a UI-focused follow-up.
Code owners: (DR-16) move sell authority/refund/destruction server-side (mirror the DR-6 server-PVF validation) or add a BattlEye scripts.txt filter; (DR-17) assign distinct IDDs to EASA/Economy dialogs. Ledger: UI/HUD Auth/PV advanced; economy thread (build/buy/sell) now fully characterized.
Lane server-loop-candidates-verify. Adversarial verification of two Cicero candidates from the Server gameplay runtime atlas; both confirmed at source with exact impact.
DR-18 — Supply-mission cooldown key casing mismatch → nil-throw on first check — Medium (correctness) — confirms Cicero
setVariable/getVariable keys are case-sensitive in Arma 2 OA (unlike SQF identifiers). The seed and the readers disagree by one letter:
-
Common/Init/Init_Town.sqf:35:_town setVariable ["lastSupplyMissionRun", 0];— lowercasel. -
Server/Module/supplyMission/isSupplyMissionActiveInTown.sqf:8:getVariable "LastSupplyMissionRun"— capitalL. Same capital form is written bysupplyMissionStarted.sqf:8andsupplyMissionActive.sqf:6.
So the 0 seed lands in a slot nothing reads, and "LastSupplyMissionRun" is nil until the first mission completes. The cooldown check then runs:
if (((_lastActivationTime + WFBE_CO_VAR_SupplyMissionRegenInterval) > time) && (_lastActivationTime != 0)) then {...}On a never-run town _lastActivationTime is nil → nil + interval throws ("Type Nothing, expected Number"), aborting the handler before it publishes WFBE_Server_PV_IsSupplyMissionActiveInTown — so the client's cooldown query can get no response on first use. The mis-cased seed defeats exactly the != 0 guard it was meant to satisfy. Fix: make the seed key "LastSupplyMissionRun", or read with a default: getVariable ["LastSupplyMissionRun", 0].
DR-19 — Hosted/listen-server FPS publishers busy-loop — Medium (performance, non-dedicated) — confirms Cicero
Both server FPS publishers put sleep 8 inside the isDedicated guard:
// Server/GUI/serverFpsGUI.sqf AND Server/Module/serverFPS/monitorServerFPS.sqf
while {true} do { if (isDedicated) then { …; publicVariable …; sleep 8; } };On a dedicated server this is fine. On a hosted/listen server or singleplayer host (isServer true, isDedicated false — and both scripts are launched server-side from Init_Server), the if is false every iteration, so while {true} spins with no sleep → a tight CPU busy-loop per script (two of them), degrading the host. Fix: either if (!isDedicated) exitWith {} at the top (don't publish FPS when hosted), or move sleep 8 outside the if so the loop always yields. (Two scripts publishing the same round diag_fps under different PV names — SERVER_FPS_GUI / WFBE_VAR_SERVER_FPS — is also redundant; consolidating would remove one loop entirely.)
Code owners: (DR-18) align the supply-cooldown key casing (or default the read) — one-line fix; (DR-19) hoist the FPS-loop sleep out of the isDedicated guard (or early-exit when not dedicated), and consider consolidating the two redundant FPS publishers. Ledger: Supply JIP/HC and server-runtime perf cells advanced.
Lane jip-headless-crosscut. Traced HQ-death detection across server, existing clients and JIP clients.
DR-20 — HQ-killed is processed once per owning-side client (no idempotency) — High (multiplayer correctness / score exploit)
Death detection for the mobile HQ is deliberately redundant (a client-local vehicle's Killed EH must run on a client):
-
Server/Construction/Construction_HQSite.sqf:89adds a server-sideKilledEH, then:91broadcasts["set-hq-killed-eh", _mhq]to the whole owning side;Server_MHQRepair.sqf:37,43do the same after a repair. -
Client/PVFunctions/HandleSpecial.sqf:34(set-hq-killed-eh) makes every owning-side client add aKilledEH that calls["RequestSpecial",["process-killed-hq",_this]]. - JIP clients additionally add it themselves at
Client/Init/Init_Client.sqf:500-503(guarded!isServer && !_isDeployed).
So N owning-side clients each hold the same Killed EH. When the HQ dies, the synced death fires every client's EH → the server receives N process-killed-hq messages → Server/Functions/Server_OnHQKilled.sqf runs N times, and it has no idempotency guard. Each run:
- awards the killer score twice (
_points = 30000/100*coefand_score = 900via twoRequestChangeScore), so total killer score ≈ 2N × the intended award; - broadcasts N× destruction /
HeadHunterReceiveBountymessages; - re-publishes
IS_<side>_HQ_ALIVE/ marker infos N times.
(The dead-MHQ wreck spawn is inside if (GetSideHQDeployStatus) and self-limits after the first run flips wfbe_hq_deployed=false; the score/message duplication does not.) On a populated server (e.g. 20 owning-side players) an HQ kill inflates the killer's score ~40×. Fix: make Server_OnHQKilled.sqf idempotent — first line if (_structure getVariable ["wfbe_hq_killed_done", false]) exitWith {}; _structure setVariable ["wfbe_hq_killed_done", true];. Keep the redundant EH registration (it ensures death is never missed regardless of MHQ locality); guard the consumer, not the producers. Pattern: "detect redundantly, act once."
- The JIP guard at
Init_Client.sqf:500(!_isDeployed) is correct: a JIP client adds the mobile-HQ EH only when the HQ is currently mobile; a deployed HQ (building) is covered by the server-side EH atConstruction_HQSite.sqf:36/Init_Server.sqf:319. JIP HQ-death detection is therefore covered — the defect is downstream duplication (DR-20), not a JIP miss. -
set-hq-killed-ehis side-filtered (SendToClients [_side, …]), so only owning-side clients register it — correct.
Code owners: add the one-line idempotency guard to Server_OnHQKilled.sqf (DR-20) — this also fixes the duplicate-score symptom on HQ kills in populated games. Ledger: JIP/HC cells advanced for victory/economy/construction (HQ-death path verified end-to-end).
Lane headless-disconnect-review. Verifies the round-1 hypothesis about HC disconnect at Server/Functions/Server_OnPlayerDisconnected.sqf.
Round 1 listed, as an unverified gotcha, "HC disconnect orphans units it created." Verified at source, that framing is wrong and is hereby downgraded: in Arma 2 OA, when any machine disconnects the engine migrates its local objects/groups to the server (ownership transfer, not deletion). HC-delegated AI is therefore not orphaned or lost on disconnect. The accurate effects are below (DR-21).
DR-21 — HC disconnect dumps delegated AI on the server with no re-delegation — Medium (performance/operational, non-data-loss)
Server_OnPlayerDisconnected.sqf HC handling:
- If
WFBE_C_AI_DELEGATION == 2andWFBE_HEADLESS_<uid>exists, it removes the HC's group fromWFBE_HEADLESSCLIENTS_IDand clearsWFBE_HEADLESS_<uid>. -
WFBE_JIP_USER<uid>is nil for an HC (HCs don't register as players viaRequestJoin), so the handlerexitWiths before the player-team/unit logic. (It does also delete anyWFBE_CLIENT_<uid>_OBJECTSregistered to that uid earlier in the handler.)
What actually happens to the AI the HC was simulating: the engine transfers those units/groups to the server, so the server's load spikes by exactly the amount the HC was offloading — the opposite of the delegation benefit, precisely when you least want it. There is no re-delegation: the disconnect handler does not hand the migrated AI to a surviving HC, and (per the round-1 init finding) WFBE_C_AI_DELEGATION is only evaluated/downgraded at boot, so a later HC reconnect does not resume offloading either. Net: HC delegation has no failover/rebalancing — a single HC drop silently re-loads the server for the rest of the match. Suggested handling: on HC disconnect, re-register migrated groups for cleanup/accounting, redirect future spawns to the server or a surviving HC, and make delegation re-evaluate when an HC (re)connects rather than only at boot. Arma 2 OA has no setGroupOwner / groupOwner live-transfer command, so full live re-delegation of already-created groups is not available; keep patch design inside this mission's remote-create-on-HC model. See AI, headless and performance and Headless delegation/failover.
Code owners: treat HC delegation as best-effort with no failover today; if HC stability matters, add cleanup/accounting re-registration and future-spawn rebalancing on HC disconnect/connect. Ledger: AI/Headless JIP/HC cell advanced; round-1 "orphan" hypothesis corrected.
Lane side-supply-delta-verify. Confirms + sharpens Faraday's "negative side-supply delta" candidate (and my round-1 "inverted guard" note) at source.
DR-22 — Overspending side supply grants a windfall instead of being floored — High (economy correctness/exploit)
The supply clamp (live in Server/Functions/Server_ChangeSideSupply.sqf, both the wfbe_supply_temp_west and …_east handlers; also present but dead in Common/Functions/Common_ChangeSideSupply.sqf) is:
_change = _currentSupply + _amount;
if (_change < 0) then {_change = _currentSupply - _amount}; // intended floor-at-0; actually a windfall
if (_change >= _maxSupplyLimit) then {_change = _maxSupplyLimit};_amount is signed — deductions are negative. When a deduction would overdraw (_change < 0), the "floor" computes _currentSupply - _amount = _currentSupply + |amount|. Example: supply 100, spend 300 (_amount = -300) → _change = -200 → guard → 100 - (-300) = 400. Trying to spend more supply than you have increases your supply by the amount you tried to spend. Any over-budget supply deduction (e.g. an upgrade/structure costing more than the side holds) flips into a gain — directly exploitable by attempting over-large spends, and it corrupts the economy generally.
Fix: floor correctly — if (_change < 0) then {_change = 0};. Apply in Server_ChangeSideSupply.sqf (both handlers). Note the matching block in Common_ChangeSideSupply.sqf is dead code: it computes _change but the function sends only [_side, _amount, _reason] over wfbe_supply_temp_<side> and the server recomputes — so fix the server copy (and optionally delete the dead client computation). Related (round-1, still open): there is no resistance-side handler for wfbe_supply_temp_*, only west/east.
Code owners: one-line floor fix in Server_ChangeSideSupply.sqf (×2 handlers) — closes the overspend windfall. Ledger: Economy/supply Auth/PV reinforced (confirmed exploit, not just "confusing").
Lane upgrade-authority-verify. Confirms Faraday's "upgrade authority gap" candidate and closes the economy-authority thread.
DR-23 — Upgrade purchasing is client-authoritative with no server validation — High (economy integrity)
Server/PVFunctions/RequestUpgrade.sqf is the whole handler: _this Spawn WFBE_SE_FNC_ProcessUpgrade; — the raw client payload [side, upgradeId, level, isPlayer] goes straight into Server/Functions/Server_ProcessUpgrade.sqf, which:
- reads
_side/_upgrade_id/_upgrade_level/_upgrade_isplayerfrom the client with no checks (no commander check, no side check, no upgrade-sequence/level check, no dependency/_LINKScheck); -
never deducts a cost — it only
sleeps_upgrade_timethen_upgrades set [_upgrade_id, current+1]. The upgrade cost is deducted client-side in the upgrade menu before the request, same as the rest of the economy.
So a modified client can forge ["RequestUpgrade",[side, id, level, false]] to grant any side a free upgrade, bypassing commander authority and cost. Secondary: _upgrade_time = (… select _upgrade_id) select _upgrade_level uses client-controlled indices → out-of-range error (minor DoS) if forged with bad ids. Fix: validate in RequestUpgrade/ProcessUpgrade — requester is the side's commander, indices in range, dependencies met and the level is the correct next step, and deduct cost server-side (mirror the DR-6 validation shape).
This is the last economic action to review, and it confirms the pattern: the entire WFBE player economy is client-authoritative —
- build structures (DR-6), buy units (DR-14), sell structures (DR-16), change side supply (DR-22, plus the overspend-windfall bug), buy upgrades (DR-23) — each lets the client decide/deduct, with the server doing at most a class-exists check.
One owner decision covers all of it: either route economic mutations through validated server PVFs (server checks commander/side/funds and applies the debit), or accept client authority and rely on BattlEye scripts.txt/PV filters. Piecemeal fixes won't close the class; the decision is architectural.
Code owners: add commander/funds/index/dependency validation + server-side cost to the upgrade path (DR-23); and make the economy-authority decision once for build/buy/sell/supply/upgrade rather than per-finding. Ledger: economy thread fully reviewed (Auth across the board characterized).
Lane missing-reference-inventory. Confirms Curie's RscMenu_Upgrade candidate at source (a representative dead/abandoned reference).
Rsc/Dialogs.hpp:2425 class RscMenu_Upgrade has onLoad = "_this ExecVM ""Client\GUI\GUI_Menu_Upgrade.sqf""" (:2428), but Client/GUI/GUI_Menu_Upgrade.sqf does not exist — only the differently-named Client/GUI/GUI_UpgradeMenu.sqf does. RscMenu_Upgrade is never opened (createDialog/cutRsc for it appears nowhere outside Dialogs.hpp); the live upgrade UI is GUI_UpgradeMenu.sqf (reached via GUI_Menu.sqf). So this is a stale dialog whose onLoad would ExecVM a missing file if it were ever opened — currently inert because nothing opens it. Fix: delete RscMenu_Upgrade (and its dangling onLoad), or repoint it at GUI_UpgradeMenu.sqf if it was meant to be the live one. Naming-drift class (GUI_Menu_Upgrade vs GUI_UpgradeMenu).
Method note: an automated "live reference → missing file" scan was attempted but its Windows-backslash path normalization was unreliable (false positives); this finding was confirmed by hand. A robust missing-reference inventory is a good future tooling task (resolve
\-separatedexecVM/ExecFSM/preprocessFilestring targets against the tree, excluding commented lines) — handed to Codex/tooling.
Code owners: remove or repoint the dead RscMenu_Upgrade dialog (DR-24). Tooling (Codex/Meitner lane): build a reliable missing-reference scanner. Ledger: UI dead-reference candidate confirmed; abandoned-code inventory still has open candidates (TaskSystem, old blink loops, WASP OnArmor/KeyDown — see round-1 WASP-Overlay + Feature-Status).
Lane ui-followups-verify. Confirms Curie's last two UI candidates at source; closes the UI follow-up items.
Rsc/Titles.hpp: class RscOverlay (:46) and class OptionsAvailable (:165) both declare idd = 10200. Titles are shown via cutRsc/titleRsc (addressed by class name, so the collision is less damaging than the dialog dup in DR-17), but any code that does findDisplay 10200 / uiNamespace lookups on that id is ambiguous. Assign distinct IDDs. (Sibling of DR-17's idd=23000 dialog dup.)
Rsc/Ressources.hpp:556 class RscClickableText has soundPush[] = {, 0.2, 1}; — the first array element (the sound file) is empty/missing (a leading comma). The correct empty-sound form is {"", 0.2, 1} (as used at Ressources.hpp:92); the line-556 form is a malformed config array. RscClickableText is a base control class used widely, so the defect propagates to inheritors. Fix: soundPush[] = {"", 0.2, 1}; (or a real sound macro like the adjacent soundEscape[] = {WFBE_SoundEscape,0.2,1}).
Code owners: assign distinct IDDs to RscOverlay/OptionsAvailable (DR-25a); fix the malformed RscClickableText.soundPush[] (DR-25b). Both Low. Ledger: UI follow-up candidates (title 10200, soundPush) now confirmed — UI cell's documented candidates are closed.
Lane external-research-integration. Steff supplied three deep-research PDFs (also given to Codex). I read two in full (Diepgaande analyse, Analyse van); the third is the same genre. Provenance check: their citations are raw.githubusercontent.com/wiki/rayswaynl/... pages + Miksuu upstream blobs — i.e. they were generated from this wiki (plus upstream as a line-level proxy), so they are downstream corroboration, not independent source verification.
The reports independently re-derive, and rate as top risks, exactly our spine: the Call Compile PVF trust boundary (DR-1) with the BattlEye kickAFK-only filter, construction client-authority (DR-6), callExtension/external-trust (DR-7), the UpdateSupplyTruck config-gated latent breakage (our Feature-Status sharpening), the town-AI despawn player-vehicle risk (our AI/headless note), the PR#1 Killed-EH leak, and MASH-marker-broken (DR-3). Their recommended fix order (static allow-list dispatch → server-side validation → reduce broadcast/centralize PV → harden callExtension) matches our DR-1/DR-6 playbooks. Our source-verified findings are a superset — the reports do not contain DR-11/15/18/19/20/22/23 (victory winner-inversion, commander-assign bug, FPS busy-loop, HQ-killed N-fold, overspend windfall, upgrade-authority), which required reading the actual .sqf rather than the wiki. Net: external review confirms the map holds up and surfaces nothing higher-severity that we missed in code.
DR-26 — License is custom/proprietary, not OSI (resolves both reports' "license unspecified") — Low (governance)
Both reports marked the license "unspecified" (they only had the wiki, not the repo root). Verified at source: LICENSE.md is a custom proprietary-style license — "Copyright (C) 2016 Spayker / (C) 2025 Miksuu", with contributions becoming the repository owner's property and reuse/distribution restricted to explicitly granted rights. Not MIT/GPL/OSI. Implication: third-party reuse or redistribution is not permitted by default; treat the repo as source-available, not open-source.
-
Discord sample metadata:
DiscordBot/preferences_sample.jsonships a concreteGuildID(440257265941872660),AuthorizedUserIDs, andDataSourcePath C:\a2waspwarfare\Data;FileConfiguration.cshas the same hardcoded fallback path. No committed token (good), but neutralize the sample identifiers / move to env-based config. (Codex/owner lane — DiscordBot is outside the Chernarus mission.) -
No CI/tests: confirmed earlier (only
.github/FUNDING.yml). For a heavilypreprocessFile-dynamic SQF codebase + generated targets, add at least SQF-syntax + generated-mission-drift + .NET build checks. (Tooling/Codex lane.)
Owner: the campaign's code findings (DR-1→DR-25) are the actionable core; the external reports add governance items (license clarity now resolved as DR-26; Discord sample hygiene; CI). Codex: fold the governance asks into External-Integrations/Tools-And-Build-Workflow as desired (its lane).
Lane weather-daynight-review. Reviewed Server/Functions/Server_DayNightCycle.sqf (Marty's hybrid accelerated cycle) + the client receiver/animation in initJIPCompatible.sqf:174-210 + Client/Functions/Client_DayNightCycle.sqf + the constants. No defect found — the system is well-designed. Recording the clean result so future passes don't re-review.
Verified:
-
No divide-by-zero in the cycle math.
_twilight_hours_per_second = _day_weighted_hours / (_day_duration_real_seconds * _twilight_weight)—WFBE_DAYNIGHT_TWILIGHT_WEIGHTis a non-zero hardcoded constant (= 3,Init_CommonConstants.sqf:88, not a param), andWFBE_DAY_DURATION's parameter values are{1,30,40,50,60,90,180}(min 1, never 0), so both divisors are always positive. -
Authority model is coherent: the server runs an authoritative accelerated clock via small per-tick
skipTimeand publishes an absolutedate(WFBE_DAYNIGHT_DATE) everyWFBE_DAYNIGHT_SERVER_SYNC_INTERVAL(30 s) for drift correction; each non-dedicated machine animates locally (Client_DayNightCycle.sqf) — consistent withskipTime/setDatebeing local-effect in Arma 2 OA. -
JIP is covered:
WFBE_DAYNIGHT_DATEis engine-synced to joiners, and the init[] Spawn { waitUntil time>0; if (!isNil "WFBE_DAYNIGHT_DATE") setDate WFBE_DAYNIGHT_DATE … }applies the current absolute date on join; live drift resumes on the next 30 s broadcast. Minor, non-defect: a JIP client'sWFBE_DAYNIGHT_DATEPVEH does not fire for the pre-join value (only the variable is synced), so the first drift-correction waits up to one sync interval — acceptable since the initsetDatealready seeds correct state. - The volumetric-clouds force-disable (perf) is documented in AI, headless and performance / Feature status register.
Outcome: weather/day-night cell → reviewed-clean. No handoff required.
Lane modules-review. Reviewed the Client/Module/ set (AFKkick, AutoFlip, CM, CoIn, EASA, Engines, MASH, Nuke, Skill, UAV, Valhalla, ZetaCargo, supplyMission) and Server/Module/. Most are config-gated cosmetic/QoL features (WFBE_C_MODULE_* flags; UAV's _button == 007 branch is comment 'DISABLED' in both uav_interface.sqf:226 and uav_interface_oa.sqf:100 — confirms the Feature-Status "UAV partial" note). The Nuke/ICBM module is the high-stakes one and carries the most severe authority defect found in the campaign.
DR-27 — ICBM nuke is fully client-authoritative; one forged publicVariable = server-applied map-wide kill — Critical (network authority / forgery)
End-to-end chain (all path:line in the Chernarus source mission):
-
Trigger is client-side and client-gated only.
Client/GUI/GUI_Menu_Tactical.sqfMenuAction == 8(the "ICBM Strike" branch, ~:463-505) deducts the fee locally (-_currentFee Call ChangePlayerFunds— itself client-authoritative, the DR-16/DR-23 economy class), spawns the strike-marker object locally ("HeliHEmpty" createVehicle _callPos), andSpawn NukeIncoming. The only ICBM gate is menu visibility (WFBE_C_MODULE_WFBE_ICBM > 0 && !IS_air_war_event,GUI_Menu_Tactical.sqf:253) — module-enable, not the per-side purchasedWFBE_upgrade_…_ICBM, and not a commander check. -
Client asks the server to detonate.
Client/Module/Nuke/nukeincoming.sqf:23:["RequestSpecial", ["ICBM",sideJoined,_target,_cruise,clientTeam]] Call WFBE_CO_FNC_SendToServer; -
Server dispatches with no validation.
RequestSpecialis a registered inbound PVF (Common/Init/Init_PublicVariables.sqf:18); its handlerServer/PVFunctions/RequestSpecial.sqfis literally_this Spawn HandleSpecial;→Server/Functions/Server_HandleSpecial.sqf"ICBM"case (:97-112):-
_base = _args select 2(client-chosen strike-position object),_target = _args select 3(client-chosen object). if (isNull _target || !alive _target) exitWith {}; waitUntil {!alive _target}; [_base] Spawn NukeDammage;-
NukeDammageis server-side (which is why the kill propagates to everyone) and is applied centered on the client-supplied_baseposition with no check that_side/clientTeamowns the ICBM upgrade, that the sender is the commander, or that funds existed.
-
Why the one server-side guard is not a security check. waitUntil {!alive _target} only requires the forger to supply some live object and then end its life — spawn any vehicle, pass it as _target, delete/kill it; or pass any alive object and kill it. It gates timing, not authority.
Impact. Any connected client can hand-craft the publicVariable RequestSpecial = ["ICBM", <anySide>, <objAtChosenPos>, <liveObjThenKilled>, <anyTeam>] and the server applies a map-wide nuke at coordinates of the attacker's choosing — repeatable, no upgrade, no commander role, no real cost. This is the apex of the client-authoritative class (DR-6 build, DR-14 buy, DR-16 sell, DR-22 supply, DR-23 upgrade): same root cause (server PVF handlers trust payload fields without re-deriving authority server-side), but the blast radius is the entire match rather than one player's wallet.
Owner decision (same lever as the economy class, higher priority). Two non-exclusive fixes:
-
Server-side authority in the
"ICBM"case: re-derive the requester from the PV sender, verify_remoteSenderis the commander of_side, verify the side'sWFBE_upgrade_…_ICBMlevel > 0 and a server-tracked cooldown/funds ledger, beforeSpawn NukeDammage. (The same_remoteSender-vs-payload pattern recommended in DR-1/DR-6.) -
BattlEye
scripts.txt/publicvariable.txt: restrict/snapshot theRequestSpecialPV so the"ICBM"selector can't be hand-injected. Defense-in-depth, not a substitute for server validation.
Handoff for Codex: this belongs in the Networking PVF-hazard table and a Feature-Status/atlas note on the Nuke module; the actionable fix is an owner decision shared with the economy-authority item already logged (DR-6/14/16/22/23).
Outcome: modules cell → Auth/PV flipped to the DR-27 finding; rest of Client/Module/ reviewed as config-gated cosmetic/QoL with the UAV-007 branch confirmed disabled.
Lane gear-easa-review. Reviewed the aircraft/vehicle loadout system (Client/Module/EASA/ + Client/GUI/GUI_Menu_EASA.sqf) and the vehicle service point (Client/GUI/GUI_Menu_Service.sqf). Result: gear/rearm is the last untracked tier of the client-authoritative economy class, plus a minor logic inconsistency.
DR-28 — Gear/EASA loadouts and vehicle rearm/repair/refuel/heal are client-authoritative; rearm & refuel skip even the client-side affordability guard — High (economy authority), class-completing
Source-verified:
-
No server PVF for gear at all.
EASA_Equip.sqfapplies the chosen loadout directly to the local vehicle (addWeapon/addMagazine, oraddWeaponTurret/addMagazineTurretfor theAW159_Lynx_BAF) and broadcasts only the setup index (_vehicle setVariable ["WFBE_EASA_Setup", _index, true],:36). There is noSendToServer/RequestSpecialanywhere in the EASA or Service flow (grep-confirmed) — the spend and the effect are entirely client-local. -
EASA cost is a client-side honor check.
GUI_Menu_EASA.sqf:46-50:if (_funds > (_row select 0)) then { … Call EASA_Equip; -(_row select 0) Call ChangePlayerFunds; … }. The price lives in the loadout row ([[Price],[Desc],[Wpn,Ammo]…],EASA_Init.sqf:8), the affordability test runs on the client, and the debit is the client-authoritativeChangePlayerFunds(the DR-16/DR-23 primitive). A modified client equips any loadout without paying. -
Service rearm/refuel deduct with NO affordability guard.
GUI_Menu_Service.sqf: rearm (MenuAction==1,:196-200) and refuel (:217-219) do-_price Call ChangePlayerFunds;unconditionally, thenSpawn SupportRearm/the refuel thread — whereas repair (:206-211,if (_repairPrice > 0)) and heal (:228-230) are guarded. So even a legit client can rearm/refuel into negative/clamped funds, and (as with all of the above) the effect threads run client-side with no server check.
Why it matters. This completes the economy-authority picture. Every WFBE spend path is now source-confirmed client-authoritative: build (DR-6) · buy (DR-14) · sell (DR-16) · supply transfer (DR-22) · upgrades (DR-23) · ICBM superweapon (DR-27) · gear/EASA + vehicle rearm/repair/refuel/heal (DR-28). There is no server-side ledger; ChangePlayerFunds and the can-afford tests are all on the honor system. The rearm/refuel missing-guard is a real but secondary inconsistency — moot against the root issue, since a cheat client bypasses the debit regardless.
Owner decision (same single lever). The one architectural decision already logged for the economy class covers DR-28 too: either (a) move spend authority server-side — a server-validated funds ledger that PVF handlers debit before applying effects — or (b) accept client-authoritative economy and lean on BattlEye scripts.txt to blunt the most trivial money/var edits. No new lever; gear simply joins the list. If (a) is ever scoped, also add the trivial if (_funds >= price) guards to Service rearm/refuel for parity with EASA/repair/heal.
Handoff for Codex: fold DR-28 into the Economy page's "all spend is client-authoritative" note and the gear/loadout atlas; it's the same owner decision, no separate workstream.
Outcome: new ledger row Gear / EASA / vehicle service → Map ✅, Auth ✅ (characterized as client-authoritative, DR-28), PV/JIP-HC 🟡, Drift ⬜; Economy row note extended to name gear as a class member.
Lane extension-globalgamestats-review. Reviewed the in-repo .NET callExtension DLL (Extension/src/**) end-to-end plus its sole SQF caller (Server/CallExtensions/GlobalGameStats.sqf). This is the second extension trust boundary (distinct from the AntiStack A2WaspDatabase DLL reviewed in DR-7..DR-10, which is not in the repo). Net: this one is currently the safe direction, but carries a dormant RCE landmine and an async void reliability bug, and is a write-only/abandoned-refactor stub.
DR-29 — GLOBALGAMESTATS extension: safe today (output discarded), but a dormant deserialization-RCE landmine + async void write race + write-only stub — Medium (latent Critical)
What it is: a one-way telemetry exporter. GlobalGameStats.sqf loops every 60 s (while {true} … sleep 60, execVM'd once from Init_Server.sqf:298) and calls
"a2waspwarfare_Extension" callExtension format ["%1,…,%6","GLOBALGAMESTATS",scoreWest,scoreEast,worldName,uptime,playerCount]. The DLL (ExtensionMethods.RvExtension, the legacy synchronous _RVExtension@12 ABI — correct for A2 OA 1.64; A3's RVExtensionArgs does not exist here) enum-validates the selector, reflection-instantiates GLOBALGAMESTATS (EnumExtensions.GetInstance → Type.GetType("GLOBALGAMESTATS")), stores the args (GameData.Instance.exportedArgs = _args) and serializes GameData to C:\a2waspwarfare\Data\database.json.
Findings (source-cited):
-
No RCE-into-SQF vector — the safe contrast to DR-7.
RvExtension's_outputStringBuilder is never written (grep-confirmed; only the parameter declaration exists atExtensionMethods.cs:12), and the SQF caller invokescallExtensionas a bare statement with no assignment (GlobalGameStats.sqf:22). So the DLL returns an empty string and SQF nevercall compiles anything from it — the exact opposite of the AntiStack DB path (DR-7), where_responseis captured and compiled. Reflection is also constrained:Enum.TryParse(ExtensionMethods.cs:29) gates the selector to theGLOBALGAMESTATSenum beforeType.GetType, so SQF cannot instantiate arbitrary CLR types. -
Dormant deserialization-RCE landmine (Low now → Critical if load is ever enabled). The commented-out load path (
SerializationManager.cs:104-130) usessettings.TypeNameHandling = TypeNameHandling.Auto;withJsonConvert.DeserializeObject<Database>(_json, settings)— the textbook Newtonsoft$typegadget sink. It is inactive today, but the feature cannot actually persist across restarts without a load path (see #3), so a future dev is likely to re-enable it. Ifdatabase.jsonis ever writable by an untrusted process (or replaced), re-enabling load = remote/local code execution on the server host. The active serializer is correctly hardened (TypeNameHandling.None,SerializationManager.cs:33) — the risk is strictly the commented load path. Recommend: delete the dead load code, or if reinstated useTypeNameHandling.None+ a fixed expected type. -
Write-only / abandoned-refactor stub. The active code only ever serializes; the entire deserialize/load path is commented out and references a different type graph (
Database,Leagues.StoredLeagues) than the liveGameDatasingleton — evidence of a half-finished refactor. Consequence: there is no cross-restart persistence today (the DLL never reads the file back), andGameData's only field is[DataMember] public string[] exportedArgs = new string[2](GameData.cs:29) — a stale initializer, since the caller now sends 5 data args (the// Todo: [3] Uptime [4] Player countcomment inGLOBALGAMESTATS.cs:9-11is also stale — both are already wired). Any wiki text implying GLOBALGAMESTATS provides durable stat persistence would be too confident; it currently produces a single overwritten JSON snapshot. -
async void+ unawaited file-create race beforeFile.Replace(Medium reliability).SerializationManager.SerializeDBisasync void; it calls the alsoasync voidFileManager.CheckIfFileAndPathExistsAndCreateItIfNecessary(dbPath, dbFileName)without awaiting (:52), then immediatelyFile.Replace(dbTempPathWithFileName, dbPathWithFileName, null)(:55).File.Replacerequires the destination to exist — on first run (nodatabase.jsonyet) the fire-and-forget create may not have completed, soFile.ReplacethrowsFileNotFoundException. PerBaseExtensionClass(:18-22) that is rethrown asInvalidOperationExceptionout of the synchronous_RVExtension@12call, which can destabilize the calling SQF/game thread; and unobservedasync voidexceptions surface as unhandled exceptions on the .NET threadpool, which can crash the host process. Recommend: make the I/O methodsasync Taskandawaitthem, or do the create synchronously beforeFile.Replace. -
Minor telemetry data-quality bug (SQF side).
GlobalGameStats.sqf:20computes_playerCount = abs(_playerCount - 1)("Exclude headless client"), which assumes exactly one HC is always connected. With 0 HCs it under-reports by 1 (1 real player → reports 0; empty server →abs(0-1)=1reports a phantom player); with 2+ HCs it over-subtracts. TwoWFBE_CO_FNC_LogContentINFORMATION lines per minute (:11"Running with old vars …",:23) also add steady RPT noise. Cosmetic/telemetry-only.
Owner decisions / handoff for Codex. Document GLOBALGAMESTATS in External integrations as a one-way, output-discarded telemetry exporter (explicitly NOT an RCE-into-SQF path, unlike the AntiStack DB), with three concrete code asks for the owner: (a) delete or harden (TypeNameHandling.None) the dead deserialize path before anyone re-enables load; (b) fix the async void create/File.Replace race; (c) optional — correct the abs(playerCount-1) HC heuristic and the stale new string[2]/Todo comments. The Extension DLL is a code artifact, not a wiki page — these are upstream code-owner items, logged here for traceability.
Outcome: Integrations row — Extension sub-target reviewed (DR-29). AntiStack DB (DR-7..DR-10) + Extension (DR-29) now both done; Discord data path + BattlEye scripts.txt/publicvariable.txt posture remain ⬜ within the bundle.
Round 21 — 2026-06-02 (Claude) — BattlEye posture (DR-30) — the "rely on BattlEye" half of every economy/forgery owner-decision is not shipped
Lane battleye-posture-review. Source-verified the repo's entire BattlEye footprint to close a loop the campaign left open across eight prior findings (DR-1 RCE dispatch + DR-6/14/16/22/23/27/28 client-authoritative economy), each of which offered remediation option (b) "accept client authority and rely on BattlEye filters." Confirms — and sharpens — the high-level posture the Codex Gibbs scout reported (Progress-Dashboard.md:23,72), and corroborates the accurate, non-overclaiming wiki text already in place (External-Integrations.md:60, Feature-Status-Register.md:32, Networking-And-Public-Variables.md:122).
DR-30 — As shipped, the BattlEye mitigation is a 22-byte AFK-kick stub: no security PV filter, no scripts.txt at all — option (b) does not exist in the repo — High (live-server hardening gap, campaign-wide)
Source facts (full repo sweep):
- The only BattlEye filter file in the repository is
BattlEyeFilter/publicvariable.txt— 22 bytes, whose entire content is:This is not a security control. The single rule is the AFK-kick feature plumbing itself://new 5 "kickAFK"Client/.../updateclient.sqfintentionally broadcastskickAFKand BattlEye acts on it becauseserverCommandkick paths are unavailable (correctly documented atExternal-Integrations.md:58andNetworking-And-Public-Variables.md:66). There is no default-deny catch-all line (e.g.5 "" !="legitPV1" !="legitPV2" …) and therefore no restriction on any forgery-class PV —RequestSpecial(the DR-27 ICBM vector),RequestStructure/RequestDefense(DR-6),RequestUpgrade(DR-23),RequestNewCommander(DR-15), or the rawServer_HandlePVF/Client_HandlePVFchannels (DR-1). Every dangerous PV passes BattlEye unfiltered. -
scripts.txtis absent (verified by name across the whole repo), as are the relevant Arma 2 OA command filters such ascreatevehicle.txt,setvariable.txt,setpos.txt,setdamage.txt,deletevehicle.txt,mpeventhandler.txt, cargo filters,teamswitch.txt,waypointcondition.txt,selectplayer.txtandattachto.txt.scripts.txtis the filter that would blunt the DR-1call compileRCE and script-command injection (createVehicle/setDamage/call compile), so its absence is the more security-relevant gap of the two. Do not countremoteexec.txthere: it belongs to Arma 3remoteExec/remoteExecCall, not Arma 2 OA. - The directory also contains a 716 KB
READ ME FIRST - Using BattlEye filter to auto kick.docx. Per the project's untrusted-content rule it was not parsed (binary Office doc); regardless, the operative deployed artifact is the 22-byte stub, and admin documentation is not a control.
Campaign-wide implication (the point of this pass). The two-option framing in DR-1/6/14/16/22/23/27/28 is misleading as-shipped: option (b) "rely on BattlEye" is not a deployed reality — choosing it means authoring and maintaining a full BE filter set from scratch (a restrictive publicvariable.txt default-deny + whitelist of the legitimate WFBE_PVF_*/direct channels keeping kickAFK, plus a scripts.txt), which is a non-trivial, error-prone, separate workstream for a Warfare mission with hundreds of PVs and easy to break legitimate play. The realistic remediation for the entire forgery/economy class therefore collapses toward (a) server-side authority in SQF (re-derive the requester/role/funds in each PVF handler before applying effects, per DR-1/DR-6), with a real BE filter set as defense-in-depth only if someone owns it.
Honest caveat (do not overstate). BattlEye filter files are normally deployed in the server's BE working directory (the BEpath), outside the mission PBO — so their absence from this repo does not prove the production server lacks them. But the repository, as the campaign's source of truth, ships only the stub; whether ocd-clan.com/Miksuu's live server maintains a fuller filter set is an explicit owner question, not a safe assumption. The wiki should keep stating (as it already does) that PVF spoofing "must not be considered protected by BattlEye."
Owner decision / handoff for Codex. No wiki rewrite needed — the existing BattlEye text is accurate and in-lane for Codex. This finding's value is the cross-link: add a one-line note to the DR-1 remediation playbook and the External integrations BattlEye section that "option (b) requires building the filter set; it is not present in-repo (only the kickAFK stub)," and pose the production-BE-config question to the server owner. Bundle the scripts.txt/server.cfg/basic.cfg absences (also flagged by the Gibbs scout) into the same hosting-hardening owner item.
Outcome: Integrations row — BattlEye sub-target reviewed (DR-30). AntiStack DB (DR-7..DR-10), Extension (DR-29) and BattlEye (DR-30) now done; only the Discord data path remains ⬜ within the bundle. Every prior economy/forgery finding's option (b) is now annotated as "not shipped."
Round 22 — 2026-06-02 (Claude) — Discord data path (DR-31) — the DR-29 deserialization landmine is LIVE in the bot, with TypeNameHandling.All
Lane discord-datapath-review. Reviewed the in-repo DiscordBot/ (.NET / Discord.Net) end-to-end — the consumer side of the GLOBALGAMESTATS extension (DR-29), closing the last Integrations sub-target. The data path is: Arma server → GLOBALGAMESTATS extension writes C:\a2waspwarfare\Data\database.json (DR-29) → DiscordBot reads it on a 60 s timer → posts a game-status embed. Net: secret hygiene is good, the inbound command surface is properly auth-gated, but the deserialization sink I flagged as dormant in the extension (DR-29 #2) is active here, and worse.
DR-31 — DiscordBot deserializes database.json with TypeNameHandling.All on a 60 s timer — live insecure-deserialization gadget sink in the token-holding process — High (insecure deserialization; local-write-gated RCE)
Source-verified:
-
The active load path uses
TypeNameHandling.All.GameData.LoadFromFile()(DiscordBot/src/ExtensionData/GameData/GameData.cs:49-56) buildsnew JsonSerializerSettings { … TypeNameHandling = TypeNameHandling.All … }andJsonConvert.DeserializeObject<GameData>(json, …)on the contents ofdatabase.json.TypeNameHandling.Allhonors$typedirectives for the root and every nested object/array — the canonical Newtonsoft gadget sink (e.g.ObjectDataProvider→ arbitraryProcess.Start). -
It runs automatically every 60 s, no interaction.
GameStatusUpdater(src/GameStatusUpdater.cs:9,19-22,84) arms aSystem.Timers.TimeratUPDATE_INTERVAL_SECONDS = 60withAutoReset = trueand callsLoadFromFile()each tick. Two more live callers:ProgramRuntime.cs:15(startup) andCommandHandler.cs:211(CreateGameStatusEmbed). So the sink is exercised continuously regardless of any auth. -
The capability is gratuitous.
GameData's only state is[DataMember] private string[] exportedArgs(GameData.cs:30) — a flat string-array DTO with no polymorphism. The writer (the extension, DR-29) serializes withTypeNameHandling.Noneand emits no$type. The reader therefore needs.None; requesting.Alladds nothing but the gadget sink. (A second, dead copyGameDataDeSerialization.HandleGameDataCreationOrLoadingusesTypeNameHandling.Auto— no callers, grep-confirmed; should be deleted too.) -
Trigger & blast radius. Not remotely exploitable as-configured:
database.jsonis normally written only by the trusted local extension. But any write-primitive toC:\a2waspwarfare\Data\database.json— a misconfigured ACL/share onDataSourcePath, a malicious mod or compromised Arma process writing there, or a future feature that ingests untrusted data into that file — yields arbitrary code execution in the DiscordBot process, which holds the Discord bot token (→ token theft + full bot/guild control). Classic local insecure-deserialization escalation.
Owner decision / fix (trivial). Change GameData.LoadFromFile() to TypeNameHandling.None (the data is a flat DTO; no behavior is lost) and delete the dead .Auto method. This also retro-closes DR-29 #2: keep the extension's deserialize path .None if it is ever reinstated. Defense-in-depth: lock down the ACL on C:\a2waspwarfare\Data so only the Arma service can write it.
Secondary observations (Low / informational):
-
Secret hygiene is good — resolves the external reports' "Discord sample hygiene" item.
DiscordBot/.gitignoreexcludestoken.txtandpreferences.json;preferences_sample.jsoncontains no token. Minor: the sample commits a real-lookingGuildID(440257265941872660) and oneAuthorizedUserIDssnowflake — these are Discord IDs, not credentials (knowing an admin's user ID grants nothing without being that user), but a sample is cleaner with placeholder zeros. -
Inbound command surface is correctly gated. Slash-command handlers check
Preferences.Instance.IsUserAuthorized(userId)(CommandHandler.cs:49,127) before privileged actions — no missing-authorization finding there. -
Three-way
exportedArgsshape drift (coupling smell). The array isnew string[2]in the extension (DR-29),new string[4]in the bot (GameData.cs:30), while the SQF sender emits 5 data fields and the bot reads index[4]. Held together only by wholesale= _argsreplacement on deserialize + bounds-guards (Length > 4, added after the commented unguardedGetGameMapAndPlayerCountatGameData.cs:138-145). Benign today, but the three sides of the contract disagree on the shape — document the canonical 5-field layout ([0]bluforScore [1]opforScore [2]worldName [3]uptime [4]playerCount) in one place.
Handoff for Codex. Document the Discord data path in External integrations: one-way pull (extension writes JSON → bot reads on 60 s timer → status embed), secret hygiene OK, command surface auth-gated; flag the TypeNameHandling.All fix as the one actionable code-owner item and cross-link DR-29/DR-31. These are code artifacts, logged here for traceability.
Outcome: Integrations row — Discord sub-target reviewed (DR-31); all four sub-targets (AntiStack DB, Extension, BattlEye, Discord) now done. Map cell can move to ✅. The DR-29 deserialization concern is now closed end-to-end (dormant in writer, live in reader, one-token fix).
Round 23 — 2026-06-02 (Claude) — generated-mission drift (DR-32): vanilla faithful, modded forks divergent, 4 modded stubs abandoned
Lane generated-mission-drift-review. Cross-cutting Drift pass: file-set + byte-level comparison of the Chernarus source mission against every generated mission (1 vanilla + 7 modded), to establish whether the DR-1..DR-31 findings (all verified against Chernarus) propagate, and whether LoadoutManager generation introduces divergence. This is the single highest-leverage Drift result — it characterizes the Drift dimension for all subsystems at once.
DR-32 — Generated missions fall into three fidelity tiers; modded missions are divergent forks or abandoned stubs, so source fixes do not propagate to them — Medium (maintainability / drift) + abandoned-code inventory
Method: relative-path file-set comm + per-file cmp of all source .sqf against each generated mission. Results (differing/common .sqf):
| Generated mission | differ/common .sqf | Tier |
|---|---|---|
Missions_Vanilla/…takistan |
15 / 671 | Faithful |
Modded_Missions/…Napf |
123 / 466 | Divergent fork |
Modded_Missions/…eden |
119 / 465 | Divergent fork |
Modded_Missions/…lingor |
104 / 417 | Divergent fork |
Modded_Missions/…smd_sahrani_a2 |
4 / 4 (4 files total) | Abandoned stub |
Modded_Missions/…dingor |
3 / 3 (20 files total) | Abandoned stub |
Modded_Missions/…tavi |
2 / 2 (3 files total) | Abandoned stub |
Modded_Missions/…isladuala |
1 / 1 (1 file total) | Abandoned stub |
-
Vanilla Takistan is a faithful regeneration. Only 15
.sqfdiffer, and all are map-config, not logic: the per-factionCore_Artillery/Artillery_*.sqf,Config_GUE.sqf,GUI_Menu_Help.sqf,WASP/unsort/StartVeh.sqf, andServer/Init/Init_Server.sqfwhose sole diff is one line —["SET_MAP", 1]→["SET_MAP", 2](the AntiStack DB map identifier). Plus textures (US/CDF skins → desert skins) and 3 extra nativeArtillery_{TKA,TKGUE,US}.sqf. All other 656 logic files are byte-identical. → Every DR-1..DR-31 finding propagates verbatim to vanilla Takistan; a fix to the Chernarus source + regen corrects both. The Drift dimension for the source→vanilla path is clean. -
Napf / eden / lingor are heavily divergent full forks. 104–123 of ~465 logic files differ from source — including security-critical files I reviewed:
Server_HandlePVF.sqf(DR-1),Server_HandleSpecial.sqf(DR-27),server_victory_threeway.sqf(DR-11),Server_ProcessUpgrade.sqf(DR-23),Server_OnHQKilled.sqf(DR-20),Server_OnPlayerDisconnected.sqf(DR-21),Init_PublicVariables.sqf,initJIPCompatible.sqf. The divergence is hand-customized behavior, not just config: e.g. Napf'sServer_HandleSpecial.sqf"ICBM" case additionally spawns threeBO_GBU12_LGBlaser-guided bombs around the target (absent in source). This is consistent with DR-4 (modded propagation is commented out atTools/LoadoutManager/.../SqfFileGenerator.cs:132) — the modded missions are not regenerated from source; they are independent forks. Consequence: a fix to the Chernarus source does not reach Napf/eden/lingor; the DR vulnerability classes almost certainly persist there (same architecture) but at different lines/with different effects, so each fork needs its own review and manual fix propagation. -
smd_sahrani_a2 / dingor / tavi / isladuala are abandoned stubs. They have only a tiny fraction of the real mission tree; most are missing
Server/,mission.sqm, theWASP/overlay,description.ext, and essentially all logic. They cannot load as functional Warfare missions. These are incomplete scaffolds committed to the repo — an abandoned-code/inventory item.
Wave S 2026-06-02 refinement: Napf/eden/lingor should be treated as partial forks, not drop-in runnable missions from the checkout. eden lacks tracked version.sqf; Napf lacks tracked mission.sqm and version.sqf; lingor lacks tracked mission.sqm, description.ext, initJIPCompatible.sqf and version.sqf. The stub tier remains non-runnable; dingor has a description.ext that includes missing version.sqf.
Owner decisions / handoff. Three explicit choices for the code owner, all logged for Codex to fold into Tools and build workflow / a generated-mission status table (Codex's lane):
- Stub missions (sahrani/dingor/tavi/isladuala): complete via regeneration or remove them — they are dead weight and misleading as "supported maps."
- Divergent forks (Napf/eden/lingor): pick a maintenance model — (a) re-enable modded propagation (DR-4) and regenerate from the hardened source, accepting loss of the hand-customizations (e.g. Napf's GBU ICBM), or (b) formally treat them as independent forks and apply every DR-1..DR-31 fix to each by hand. Today they silently drift.
- All security fixes: apply to the Chernarus source first (propagates to vanilla Takistan on regen), then deliberately propagate to the 3 forks.
Outcome: Drift dimension characterized across the whole codebase. Source→vanilla path is faithful (DR findings transfer verbatim); modded missions are out-of-scope forks/stubs flagged here. Ledger Drift cells updated to reference DR-32 (faithful-to-vanilla ✅; modded divergence is an owner decision, not a review gap).
Lane factory-perf-jip-review. Filled the two ⬜ cells on the Factory/purchase row by source-reviewing the unit-production path: Client/GUI/GUI_Menu_BuyUnits.sqf (queue gate) → _params Spawn BuildUnit → Client/Functions/Client_BuildUnit.sqf (the production loop), plus the WFBE_C_QUEUE_* counters seeded in Client/Init/Init_Client.sqf. Production runs entirely on the buyer's client (group player, local CreateUnit/CreateVehicle). Two real defects (one JIP/HC, one Perf) plus a network-churn note.
DR-33a — Empty-vehicle purchase leaks the buyer's WFBE_C_QUEUE counter → silent per-factory soft-lock — Medium (JIP/HC / client-state leak)
WFBE_C_QUEUE_<type> is a client-local counter (seeded in Init_Client.sqf:185+, e.g. BARRACKS_MAX=10, LIGHT_MAX/HEAVY_MAX=5). The buy gate increments it before producing and blocks at the cap:
-
GUI_Menu_BuyUnits.sqf:145-146:if (WFBE_C_QUEUE_<type> < WFBE_C_QUEUE_<type>_MAX) then { …+1; _params Spawn BuildUnit }else:158"queue max" hint. -
Client_BuildUnit.sqf:469decrements it at the normal tail of the script.
But the vehicle branch has an early if (!_driver && !_gunner && !_commander) exitWith {} (Client_BuildUnit.sqf:365) — for a crewless vehicle purchase (all crew unchecked, a legitimate option) — which returns before the tail decrement at :469. So each empty-vehicle buy permanently increments the buyer's local queue counter without ever decrementing it. After _MAX such purchases (5 for Light/Heavy) the GUI gate at :145 silently refuses all further production from that factory type for the rest of the match — a slow soft-lock that presents as a mysterious "can't buy / queue full" with nothing actually queued. Reachable in normal play. Fix: move the WFBE_C_QUEUE (and unitQueu, :467) decrements before/around the empty-vehicle exitWith, or restructure so all exit paths decrement (e.g. a single cleanup block).
DR-33b — Per-unit sleep 4 queue poll re-broadcasts the building's queue on every mutation; non-unique queue token — Low/Medium (Perf / network churn + latent correctness)
-
Network churn. Each queued unit gets its own
Spawn BuildUnit, which busy-waitswhile {_unique != _queu select 0 …} { sleep 4; … }(:180-199) and writes_building setVariable ["queu", _queu, true]— a global broadcast — on every enqueue (:172), timeout-advance (:191) and completion (:207). With several factories producing across a full server, every 4 s tick that advances or cleans a queue broadcasts that building's wholequeuarray to all machines. Bounded but avoidable; consider a server-owned queue or a non-broadcast local timer. -
Non-unique token. The per-item identity is
varQueu = random(10)+random(100)+random(1000)(:168) — a ~0–1110 value space, not unique. Two concurrently-queued items can collide on_unique, breaking the_unique != _queu select 0front-of-queue test (an item may wait forever or two may think they're first). Low probability per pair but non-zero on a busy factory. Fix: use a monotonic counter ordiag_tickTime-seeded id. -
Orphan token on disconnect (minor). Because the loop + the front-token removal (
:206) run on the buyer's client, a buyer disconnecting mid-production leaves their_uniquetoken in the building's broadcastqueu; it self-heals only if another buyer is queued behind to run the_ret > _longesttimeout-cleanup (:187-192). The localWFBE_C_QUEUEcounter is not leaked across clients (it dies with the buyer). Stale shared data, low impact.
Handoff for Codex. Document the production queue model in the Factory/purchase atlas: client-owned per-unit producer, broadcast queu token list, per-client WFBE_C_QUEUE caps. The two fixes (DR-33a decrement-on-all-paths; DR-33b unique token + reduce broadcast) are concrete code-owner items, not architectural decisions. Note DR-33a propagates to vanilla Takistan verbatim (DR-32) and likely exists in the 3 forks too.
Outcome: Factory/purchase row — Perf and JIP/HC cells filled (DR-33). The row's remaining 🟡 (Auth/PV) is the DR-14 client-authoritative-purchase architectural ceiling (economy class, owner decision).
Round 25 — 2026-06-02 (Claude) — respawn / MASH markers (DR-34): MASH map-marker feature is dead on both ends
Lane respawn-mash-review. Reviewed the respawn UI (Client/Functions/Client_UI_Respawn_Selector.sqf) and the MASH respawn-marker chain (Server/Module/MASH/MASHMarker.sqf ↔ Client/Module/MASH/receiverMASHmarker.sqf), with wiring confirmed in Init_Client.sqf / Init_Server.sqf. Extends the earlier DR-2 note ("MASH markers are dead receive-side") to a full both-ends diagnosis.
DR-34 — MASH map-marker feature is fully dead (send trigger never broadcast + client receiver commented out); the live server PVEH is orphaned — Low/Medium (broken/abandoned feature; UX)
MASH tents are a real deployable officer feature (Client/Module/Skill/Actions/Officer_Undeploy_MASH.sqf exists), but the map marker that should show a team its MASH locations does nothing, because all three links are broken or orphaned:
-
Client receiver is commented out.
Init_Client.sqf:132://WFBE_CL_FNC_ReceiverMASHmarker = Call Compile preprocessFileLineNumbers "Client\Module\MASH\receiverMASHmarker.sqf";— so no client ever registers theWFBE_SE_MASH_MARKER_SENTevent handler; the receiver inreceiverMASHmarker.sqfis never installed. -
The trigger PV is never broadcast.
WFBE_CL_MASH_MARKER_CREATEDappears in the repo only as the server'saddPublicVariableEventHandlerregistration (MASHMarker.sqf:1). No client deploy path ever doesWFBE_CL_MASH_MARKER_CREATED = […]; publicVariable …, so the server handler can never fire. -
The server handler is live but orphaned.
Init_Server.sqf:70actively compilesWFBE_SE_FNC_MASH_MARKER(=MASHMarker.sqf), registering a PVEH for a PV (WFBE_CL_MASH_MARKER_CREATED) that nothing emits — harmless dead weight that looks active in a grep but does nothing in composition. (Line 92 is a duplicate, commented.)
Net: deployed MASH tents produce no map markers for the owning side. Confirms and extends DR-2.
Latent JIP gap if revived (note for whoever fixes it). Even with both ends re-enabled, the marker is delivered by publicVariable "WFBE_SE_MASH_MARKER_SENT" — a single global overwritten on each deploy (not a list) and not replayed to join-in-progress clients. So a revived feature would: (a) show JIP joiners no markers for MASH deployed before they joined, and (b) only ever carry the most-recent MASH in the synced value. A correct revival needs a server-held list + a JIP re-send on join (the same pattern the construction/HQ-killed code uses via Server_HandleSpecial "set-…" re-sends).
Secondary (Low):
-
Respawn selector is a ~33 Hz local loop.
Client_UI_Respawn_Selector.sqf:19-33runswhile {!isNil 'WFBE_MarkerTracking'} do { sleep 0.03; … }, animating a pulsing local marker (setMarkerDirLocal/SizeLocal/PosLocal) — network-free and bounded to while the respawn UI is open, butsleep 0.03cannot be honored by the SQF scheduler so it effectively runs every frame. Acceptable for a transient UI; flagged for completeness. -
Non-unique marker name (dead code, DR-33b class).
receiverMASHmarker.sqf:12builds the marker name withround random 50000(collision-prone) and later deletes acreateMarkerLocalmarker with the globaldeleteMarker(local/global mismatch). Moot while the receiver is disabled; fix if revived.
Handoff for Codex. Mark the MASH map-marker feature as dead/abandoned in the Feature status register and the relevant marker/respawn docs (Codex's lane), with the revival recipe above (server-held list + JIP re-send + unique names + fix publicVariable JIP gap). Owner decision: revive the feature or remove the dead receiverMASHmarker.sqf + orphaned Init_Server.sqf:70 registration.
Outcome: Markers/respawn — MASH marker chain reviewed (DR-34): dead both ends + orphaned server PVEH; respawn selector Perf characterized. Markers row PV/JIP-HC cells reference DR-34.
Round 26 — 2026-06-02 (Claude) — parameters / localization integrity (DR-35): clean, with 2 dead-action confirmations
Lane params-localization-review. Reviewed the two never-covered cross-cutting areas: localization integrity (do localize/$STR_ references resolve?) and the mission parameters system. Result: localization is clean once case-folding and dead-code are accounted for; the params system is live and correctly wired.
DR-35 — Localization integrity is clean (no live broken strings); parameters system is live and correctly wired; 2 dead WASP actions confirmed — Informational (reviewed clean + abandoned-code)
Method matters (the trap that produces false findings). Arma 2 OA stringtable lookup is case-insensitive, but text-diff tools are not. A naïve case-sensitive set-difference of the 204 static localize "STR_…" keys against the 1289 stringtable.xml keys reports 4 "missing"; after lowercasing both sides it drops to 3, and after checking each reference site for liveness it drops to 0 live bugs:
-
STR_WF_UPGRADE_uav_Desc— false positive (casing): defined asSTR_WF_UPGRADE_UAV_DESC; resolves at runtime. -
STR_EP1_UAV_action_exit(Client/Module/UAV/uav_interface_oa.sqf:25, live) — engine-provided: theSTR_EP1_*namespace is supplied by the Arma 2 OA base game's global stringtable, not the mission; resolves at runtime. -
STR_WASP_actions_OnArmorandSTR_WF_Gear— referenced only in commented-out lines (WASP/actions/AddActions.sqf:4,10-12, the dead "ride-on-armor" and "gear your unit" WASP actions). Dead code; the missing keys are moot.
Config-side $STR_ references in .hpp/.ext (excluding engine STR_EP1_/STR_DN_/STR_USRACT prefixes) all resolve. So no live missing-localization display bug exists. The stringtable carries ~1085 keys not hit by any static localize — a large legacy surface typical of a long-lived WFBE fork, not a defect (some are reached by config $STR_, engine, or removed features).
Parameters system — live and correct. Common/Init/Init_Parameters.sqf iterates missionConfigFile >> "Params" and sets each configName as a missionNamespace variable, taking paramsArray select _i in multiplayer and the param's default in single-player. Wiring confirmed: initJIPCompatible.sqf:121 runs it in MP; the parameter-display dialog is loaded via Rsc/Dialogs.hpp:3136 (onLoad ExecVM GUI_Display_Parameters.sqf), defined in Rsc/Parameters.hpp. This is the canonical A2 OA pattern. One fragility note (not a defect): the paramsArray select _i ↔ Params iteration is index-aligned, so inserting/removing a param without keeping class Params order in sync would silently shift every later parameter's value — worth a comment in the config for future editors.
Abandoned-code inventory (adds to DR-32/DR-34). WASP/actions/AddActions.sqf contains commented-out OnArmor (ride-on-tank: GetOnArmor.sqf/GetOnArmorBots.sqf/GetOutBots.sqf) and GearYourUnit actions — dead WASP features whose localization keys were never added. Confirms the earlier "WASP OnArmor/KeyDown abandoned" suspicion.
Handoff for Codex. Optionally note in the WASP overlay page that AddActions.sqf carries dead OnArmor/Gear actions, and add a one-line "keep class Params order stable (index-aligned to paramsArray)" caution to any parameters documentation (Codex's lane). No code defect to fix; the dead WASP actions are an owner cleanup decision (remove vs revive).
Outcome: parameters/localization reviewed — clean; localization integrity verified (no live broken keys), params system confirmed live/wired, 2 dead WASP actions logged. New ledger row Parameters / localization → reviewed-clean (DR-35).
Round 27 — 2026-06-02 (Claude) — victory/endgame Perf + JIP/HC (DR-36); source mechanism for DR-11/DR-13
Lane victory-perf-jip-review. Filled the Victory/endgame Perf + JIP/HC cells by reviewing the loop in Server/FSM/server_victory_threeway.sqf (the sole victory FSM, execVM'd unconditionally at Server/Init/Init_Server.sqf:528) and the end-of-match DB-flush tail, and traced the win-condition expression to a source-level root cause for the previously-observed DR-11/DR-13.
DR-36 — Victory loop Perf clean + JIP/HC server-authoritative; the win-condition guard/precedence is the source of DR-11/DR-13 double-fire — Low (Perf/JIP clean) + Medium (the confirmed correctness bug)
Dual-purpose finding — disambiguate when citing: DR-36 records two things: (1) a clean Perf/JIP review of the victory loop (no defect on those dimensions), and (2) the root-cause mechanism for the separate correctness bugs DR-11 (winner inversion, High) and DR-13 (duplicate game-end). Cite "DR-36" for the mechanism/fix; cite DR-11/DR-13 for the severity/impact.
Perf — clean. The detection loop runs every _loopTimer = 80 seconds (:6,46) with cheap per-side work (GetSideHQ/GetSideStructures/GetTownsHeld + 4× GetFactories, :14-21). No hot loop, no per-frame churn. Minor: _innerTimer is incremented (:47) but never read (dead variable); _miniSleep = 0.05 paces only the one-time end-of-match per-player DB STORE (:60-82). No perf trap.
JIP/HC — server-authoritative, one narrow gap. Detection runs server-only on server-authoritative state; headless clients don't participate (correct). Endgame is pushed to clients via [nil,"HandleSpecial",["endgame", sideID]] Call WFBE_CO_FNC_SendToClients (:24); gameOver/WFBE_GameOver are set server-side (:32-33) and WFBE_GameOver is not broadcast. The only gap: a player joining in the brief endgame window (between the broadcast and failMission "END1" at :88) won't receive the outro, because SendToClients is not replayed to JIP joiners — moot in practice since the mission is tearing down.
Confirmed source mechanism for DR-11 (winner inversion) + DR-13 (duplicate LogGameEnd). The win check (:23):
if (!(alive _hq) && _factories == 0 || _towns == _total && !WFBE_GameOver) then {
By SQF precedence (&& binds tighter than ||) this is ((!alive _hq) && _factories==0) || (_towns==_total && !WFBE_GameOver) — so the !WFBE_GameOver guard covers only the "holds-all-towns" clause, not the "HQ-destroyed elimination" clause. Combined with the enclosing forEach WFBE_PRESENTSIDES - [WFBE_DEFENDER] (:43) having no break/exit after a winner is declared, if two sides are eliminated within the same 80 s tick the elimination clause fires again for the second side: a second ["endgame",…] broadcast, a second WFBE_CO_FNC_LogGameEnd (:41), and WF_Logic setVariable ["WF_Winner", _x] (:31) overwritten with the opposite side (the _side = west; if (_x==west) _side=east swap at :35-39 then logs the inverted winner). That is the exact mechanism behind DR-11's inverted persisted winner and DR-13's duplicate game-end. Fix (one place): parenthesize and guard both clauses with !WFBE_GameOver, and exitWith/break the forEach (and the while) once gameOver is set, so only the first-detected winner is recorded.
Also re-confirms DR-12: the detection block is gated by if (_victory == 0) where _victory = WFBE_C_VICTORY_THREEWAY (default 0). When threeway is enabled (_victory != 0), the entire detection block is skipped and the loop just sleeps — i.e. threeway mode has no victory detection.
Handoff for Codex. This is a code-owner fix already tracked under DR-11/DR-13; this round adds the precise path:line mechanism + the two-part one-line fix. No new wiki page needed — cross-link from the victory rows of Feature status register to DR-36 for the root cause.
Outcome: Victory/endgame row — Perf and JIP/HC cells filled (DR-36): Perf clean, JIP server-authoritative (narrow endgame-join gap noted); DR-11/DR-13 now have a source-level mechanism + fix.
Round 28 — 2026-06-02 (Claude) — boot/lifecycle Perf + JIP/HC (DR-37): reviewed clean, one robustness note
Lane boot-lifecycle-perf-jip-review. Filled the Boot/lifecycle Perf + JIP/HC cells by reviewing the role router (initJIPCompatible.sqf) and the client boot chain (Client/Init/Init_Client.sqf), with the wait-chain cross-referenced against Lifecycle wait-chain. Result: boot is well-architected for JIP and Perf-clean; one robustness gap worth a defensive fix.
DR-37 — Boot Perf clean + JIP state-sync comprehensive; the post-join waitUntil chain has no timeouts (a never-set synced var hangs the JIP client) — Low (reviewed clean + robustness note)
Perf — clean. All boot blocking-waits are bare waitUntil {cond}, which the A2 OA scheduler evaluates once per frame and yields between (not a CPU busy-spin like a sleepless while), and every condition is cheap (!isNil, !isNull player, time>0, !isNil {logic getVariable …}). One wait uses the throttle idiom waitUntil {sleep 0.5; visibleMap} (Init_Client.sqf:248) — deliberately evaluates every 0.5 s instead of per-frame, a good pattern. The while {true} { sleep 0.1; … exitWith … } loops at Init_Client.sqf:419/444 are not perpetual 10 Hz loops — they are bounded join-handshake polls (see below) that exit on ACK. No boot perf trap. (The genuinely long-running client loops — RHUD/marker updaters at :522/:864 — belong to the UI/Markers rows already covered, each with its own internal sleep.)
JIP/HC — comprehensive and correct. initJIPCompatible.sqf routes roles cleanly: server (isHostedServer || isDedicated), client part II (isHostedServer || (!isHeadLessClient && !isDedicated)), headless (isHeadLessClient). A JIP client:
- syncs time/date via the engine-synced
WFBE_DAYNIGHT_DATE(orskipTime (time/3600)catch-up on the disabled path) —:189-205, reviewed clean in Round 17; - syncs teams by waiting on the synced
WFBE_PRESENTSIDESthen per-sidewfbe_teams(:225-234); - pulls all remaining client state from broadcast logic-object variables via a serial
waitUntil {!isNil {WFBE_Client_Logic getVariable "wfbe_…"}}chain (Init_Client.sqf:367-502: structures, commander, radio_hq(+id), startpos, hq, hq_deployed, votetime). -
Robust join handshake: the
RequestJoin→ACK poll (:416-429) polls at 10 Hz, re-sends after a 30 s timeout, and fails the client back to the lobby on team-stack/swap — a well-defended one-time handshake.
The one robustness gap. Unlike the join handshake, the post-join state-sync waitUntil chain has no timeouts. Each step blocks on a synced wfbe_* logic variable; in normal operation all are reliably setVariable [...,true] server-side so the chain completes, but if a server-side regression ever fails to set one (e.g. wfbe_radio_hq_id, :397), the JIP client hangs forever at that step with no fallback or log past it — presenting as a "stuck on black screen at join" with no diagnostic. Not a live bug (the variables are set today), but a fragility: consider a waitUntil {!isNil … || (_t = _t + …; _t > N)} timeout with a logged warning, mirroring the handshake's own retry discipline.
Handoff for Codex. No code defect to fix and no wiki rewrite needed; optionally note in Lifecycle wait-chain that the post-join wfbe_* waits are timeout-less (a single missed server broadcast = permanent JIP hang) as a known robustness characteristic. Owner decision: add defensive timeouts or accept the current fail-silent behavior.
Outcome: Boot/lifecycle row — Perf and JIP/HC cells reviewed clean (DR-37); role routing + JIP state-sync confirmed correct; timeout-less post-join wait-chain logged as a robustness note.
Round 29 — 2026-06-02 (Claude) — PV/networking dispatch Perf + JIP/HC (DR-38): the per-message recompile = the DR-1 fix
Lane pv-dispatch-perf-jip-review. Filled the PV-dispatch Perf + JIP/HC cells by reviewing the dispatch hot path (Server/Functions/Server_HandlePVF.sqf, Client/Functions/Client_HandlePVF.sqf) and the registration/precompile in Common/Init/Init_PublicVariables.sqf. (Auth/PV/RCE already covered by DR-1.)
DR-38 — PVF dispatch recompiles the command string per inbound message; the lookup that fixes DR-1's RCE also removes the recompile. JIP/HC clean — Low/Medium (Perf, converges with DR-1) + JIP reviewed clean
Current status 2026-06-21: this recompile finding is source-present/fixed on current stable origin/master@0139a346 for source Chernarus and maintained Vanilla Takistan. Both roots now use missionNamespace getVariable _script plus typeName == "CODE" guards in the server and client dispatchers. Miksuu b8389e74 and origin/perf/quick-wins@0076040f still use Spawn (Call Compile _script) in both maintained roots, and current stable still needs a registered-handler allowlist/rejection log before dispatcher hardening is fully closed.
Perf. Both dispatchers end with _parameters Spawn (Call Compile _script) (Server_HandlePVF.sqf:14, Client_HandlePVF.sqf:22), so every inbound PVF message runtime-compiles the sender-provided command string. This is per-action (build/buy/construct/upgrade/join/server-pushes), not per-frame, so bounded — but it is avoidable and redundant: Init_PublicVariables.sqf already pre-compiles every PVFunction once at init into SRVFNC<name>/CLTFNC<name> globals (:44 CLTFNC%1 = compile preprocessFileLineNumbers …, :49 SRVFNC%1 = …), and binds the per-command WFBE_PVF_<name> channels to the dispatchers (:45,50). The dispatcher discards that precompiled work and recompiles the string each message. Resolving the handler by lookup — call (missionNamespace getVariable _validatedName) against the known SRVFNC*/CLTFNC* set — eliminates the per-message compile entirely. This is the same change as the DR-1 remediation: validating/looking up a name instead of compile-ing a sender-chosen string closes the RCE and the recompile in one edit. (Secondary: Spawn per message creates a scheduled script per message — justified because handlers use sleep/waitUntil, but it adds scheduler pressure under PVF floods; lower priority.)
JIP/HC — clean. The dispatchers are registered via addPublicVariableEventHandler on the WFBE_PVF_<name> channels in Init_PublicVariables.sqf (:45 client if (!isServer || local player), :50 server if (isServer)), which runs inside Init_Common on every machine including JIP clients during their own init — so a joiner installs its PVF handlers on join and processes all subsequent messages. PVFs are transient events, not state, so nothing needs replaying to joiners (the only replay burden is the separate broadcast-variable state-sync layer, DR-37). The client destination routing (Client_HandlePVF.sqf:12-15: nil = broadcast, SIDE = sideJoined match, STRING = getPlayerUID player match) resolves correctly for joiners. No JIP gap in the dispatch layer; no headless-specific dispatch issue beyond the AI-delegation locality already covered in DR-21.
Handoff for Codex. No new wiki page; fold the Perf observation into the Networking DR-1 remediation note as "the validated-lookup fix also removes a per-message compile," so the owner sees the security fix is free on Perf. JIP-clean result can be stated in the same section.
Outcome: PV/networking dispatch row — Perf and JIP/HC cells filled (DR-38): Perf = avoidable per-message recompile (fixed by the DR-1 lookup change); JIP/HC reviewed clean. The row's remaining work is the DR-1 owner decision (validate-before-execute), which now also carries a Perf benefit.
Round 30 — 2026-06-02 (Claude) — supply missions Perf + JIP/HC (DR-39): dead twin loop + pull-based JIP done right
Lane supply-missions-perf-jip-review. Filled the Supply-missions Perf + JIP/HC cells by reviewing the server module (Server/Module/supplyMission/*) and its client consumers (Client/Module/supplyMission/*). (Auth covered by DR-18 cooldown-casing + the PR#1 helicopter review.)
DR-39 — Dead duplicate supplyMissionActive.sqf; origin/master live loop scans all objects every 3 s; JIP cooldown status is correctly pull-based — Low/Medium (abandoned-code + Perf; JIP reviewed clean)
Abandoned-code: a dead twin. Two near-identical supply-mission tracking loops exist. The live one is supplyMissionStarted.sqf — it self-registers "WFBE_Client_PV_SupplyMissionStarted" addPublicVariableEventHandler { … } (:1), so compiling it (Init_Server :68 → WFBE_SE_FNC_SupplyMissionStarted) installs the handler. The dead one is supplyMissionActive.sqf — a plain function body (no PVEH; takes _this select 0/1/2, runs while {alive _truck && !_completed} {sleep 2}), compiled to WFBE_SE_FNC_SupplyMissionActive (Init_Server :81) but never called anywhere (grep-confirmed: no caller, no self-registration). It is the superseded older twin of supplyMissionStarted's spawn body (same LastSupplyMissionRun set, same SupplyMissionTimerForTown spawn, same truck-alive poll). Owner cleanup: delete supplyMissionActive.sqf + its Init_Server:81 compile, or wire it if a second path was intended. Adds to the abandoned-code inventory (DR-32/DR-34/DR-35 class).
Perf (live path). Each active supply mission spawns one server-side while {alive _associatedSupplyTruck} { sleep 3; ... } loop (supplyMissionStarted.sqf:20-69). On current source/stable/upstream/perf, the per-tick cost is still nearestObjects [(getPos _truck), [], 80] at supplyMissionStarted.sqf:24-28 — an all-object-types scan in an 80 m radius every 3 s, then a Base_WarfareBUAVterminal post-filter. Release 7ff18c49 carries a PR #1-compatible typed scan at :52,58 in both maintained release roots, including heli 400 m / truck 80 m radius selection and the heli 2D distance gate. The 8 m nearby-player/object scan at current branch :44 intentionally remains broad because it runs only once at delivery and is looking for player/vehicle occupants, not command-center structures.
JIP/HC — handled well (the positive counterexample to DR-34). Supply-mission cooldown status uses an on-demand request/response, not a fire-and-forget push: a client broadcasts WFBE_Client_PV_IsSupplyMissionActiveInTown; the server PVEH (isSupplyMissionActiveInTown.sqf) computes the cooldown from _sourceTown getVariable "LastSupplyMissionRun" vs WFBE_CO_VAR_SupplyMissionRegenInterval and answers via WFBE_Server_PV_IsSupplyMissionActiveInTown; the client (townSupplyStatus.sqf) stores it per-town. So a JIP joiner gets correct state simply by asking — no replay logic needed, unlike the MASH marker (DR-34) which pushed once and missed joiners. The per-mission tracking loop is server-side and keyed on the truck object, so it correctly survives the starting player's disconnect (truck ownership migrates to the server, DR-21). Minor: the cooldown answer is broadcast to all clients (publicVariable, :18) rather than targeted to the requester — every client re-stores the town's cooldown on each query (small redundant network; could target the asker). The DR-18 LastSupplyMissionRun casing concern lives in this subsystem and is already filed.
Handoff for Codex. Note the dead supplyMissionActive.sqf/WFBE_SE_FNC_SupplyMissionActive in the Supply mission architecture page (Codex's lane) as an abandoned duplicate; record the pull-based cooldown query as the JIP-correct pattern. Code-owner items: remove the dead twin; adopt the narrowed nearestObjects filter on origin/master; optionally target the cooldown response.
Outcome: Supply missions row — Perf and JIP/HC cells filled (DR-39): Perf = origin/master all-object nearestObjects poll (branch/release narrowed; master adoption + smoke pending) + dead twin loop; JIP reviewed clean (pull-based status, server-side tracking). The row's Auth 🟡 remains the DR-18 + PR#1 items (owner).
Lane wasp-overlay-perf-jip-review. Filled the final 🟡 Perf cell and ⬜ JIP/HC cell — the WASP overlay (WASP/*, the project-specific subtree). Reviewed against the WASP overlay page; live wiring confirmed in Client/Init/Init_Client.sqf.
DR-40 — WASP Perf clean except one sleepless display-wait busy-spin; JIP/HC correct (per-client init); old WASP init path is dead — Low (Perf nit + reviewed clean)
Live wiring (JIP-correct). The active WASP components are all execVM/call'd from Client/Init/Init_Client.sqf, which runs on every machine including JIP clients: DropRPG.sqf (:15, player call), global_marking_monitor.sqf (:267), WASP/baserep/init.sqf (:574), WASP/actions/AddActions.sqf (:575). Each client therefore builds its own local overlay on join — JIP-correct by construction (same principle as DR-37). The old monolithic init if (local player) then {ExecVM "WASP\Init_Client.sqf"} in initJIPCompatible.sqf:243-244 is inside the commented /* Marty : old wasp script … */ block — dead, superseded by the per-component wiring above (abandoned-code, already noted on the WASP page).
Perf. Mostly clean and bounded:
-
The one nit:
global_marking_monitor.sqf:62while {time < _this} do { _display = findDisplay 54; if (!isNull _display) exitWith {…add keyUp/keyDown EHs…} }is a sleepless busy-spin — it pollsfindDisplay 54every frame for up to a 2 s window (_this = time + 2) withdisableUserInput trueduring. Bounded and one-time at init, so impact is a brief hitch, but it is a genuine CPU spin. Its own sibling at:80does it correctly:waitUntil {sleep 0.1; !isNull (findDisplay 12)}. Fix: convert:62to the same throttledwaitUntil {sleep 0.05; !isNull findDisplay 54}form. - The rest are bounded:
baserep/repair.sqfpolls atsleep 1only while a repair is active;baserep/viem.sqfsleep 3;DropRPG.sqfsleep 30is a post-drop cooldown, not a loop;AddActions.sqf:2While {!(Alive Player)} do {sleep 2}is a one-shot wait that exits when the player spawns. No sustained per-frame marker/blink loop in the live WASP code.
JIP/HC — clean. Per-client init (above) means joiners initialize WASP locally; if (local player) guards (global_marking_monitor.sqf:78, DropRPG player call) correctly scope client-local features so a headless client (no real player) skips them. No PV-replay dependency in the live WASP path (the map-marking handlers are local input EHs, not networked state).
Auth/PV note (scoped out, for a future Auth pass). WASP action authority (Action_RepairMHQDepot.sqf, DropRPG.sqf createVehicle, baserep/repair.sqf) is the WASP row's remaining 🟡 Auth/PV — several are client-local self-effect, others touch shared objects; they belong to the same client-authority question as the economy class (DR-6/14/…) and are left as an explicit owner-review item, not closed here.
Handoff for Codex. Note on the WASP overlay page: global_marking_monitor.sqf:62 should use the throttled waitUntil idiom (as :80 does); the initJIPCompatible.sqf:243-244 WASP init is dead/commented (remove). Code-owner items are the one-line :62 throttle + dead-code removal.
Outcome: WASP overlay row — Perf and JIP/HC cells reviewed (DR-40): Perf clean except the :62 sleepless display-wait (one-line fix); JIP/HC correct (per-client init). This was the last outstanding Perf/JIP-HC cell in the matrix — every subsystem's Perf and JIP/HC dimension is now source-reviewed. The residual 🟡 cells are exclusively Auth/PV owner decisions (the client-authoritative economy/forgery class DR-1/6/14/16/22/23/27/28, the victory fixes DR-11/12/13, supply DR-18/PR#1, and the WASP/modules Auth follow-ups).
Round 32 — 2026-06-02 (Claude) — ATTACK_WAVE_INIT forgeable direct-PV (DR-41); confirms Codex's pv-scout candidate
Lane attack-wave-authority-verify (collaboration-follow: source-verifying Codex's attack-wave-authority backlog candidate, status new-from-2026-06-02-pv-scout). Confirmed at source and upgraded to a finding.
DR-41 — ATTACK_WAVE_INIT is a forgeable direct publicVariable: server trusts client _supply/_side, no re-derivation/authority/cost → side-wide free units — High (economy authority / forgery; new direct-PV channel)
Chain (source-cited):
-
Client gate is advisory only.
Client/FSM/updateclient.sqf:240adds the "HEAVY ATTACK MODE" action with params[(sideJoined) call GetSideSupply, sideJoined]and condition((sideJoined) Call GetSideSupply) >= 25000— a client-side visibility/eligibility check. -
Client sends its own numbers.
Common/Functions/Common_AttackWaveActivate.sqf:6-8:ATTACK_WAVE_INIT = [_supply, _side]; publicVariableServer "ATTACK_WAVE_INIT";— a direct publicVariable to the server (not via the WFBE_PVF dispatcher). -
Server trusts the payload wholesale.
Server/Functions/Server_AttackWave.sqf:1-27("ATTACK_WAVE_INIT" addPublicVariableEventHandler):_supply = _this select 1 select 0; _side = _this select 1 select 1;then_discountPercentage = 0.7 * (0.4 + ((WFBE_C_ECONOMY_SUPPLY_MAX_TEAM_LIMIT - _supply) * (1/50000)))→ setsATTACK_WAVE_PRICE_MODIFIER(a side-wide unit-price multiplier, read byGUI_Menu_BuyUnits.sqf:90/261andClient_UIFillListBuyUnits.sqf:60) and_attackWaveLength = (1 - _discountPercentage) * 1500(a server-sidesleep). No re-derivation of the side's real supply (never callsGetSideSupply), no check that_sidematches the PV sender, and no server-side supply deduction.
Impact. WFBE_C_ECONOMY_SUPPLY_MAX_TEAM_LIMIT = 50000 (Init_CommonConstants.sqf:166), so legitimately _supply ∈ [0,50000] → modifier ∈ [0.28, 0.98] (a discount). But _supply is attacker-controlled and unvalidated: forging _supply = 50000 + 0.4·50000 = 70000 drives _discountPercentage → 0 → ATTACK_WAVE_PRICE_MODIFIER → 0 → every unit costs price × 0 = free for the chosen _side; larger forged values make the modifier negative (negative-priced units / broken pricing). The 25 000-supply cost is never deducted server-side (client gate only), so the forger pays nothing, and _side is attacker-chosen. ATTACK_WAVE_INIT is not in BattlEyeFilter/publicvariable.txt (only kickAFK, DR-30), so the channel is unfiltered. _attackWaveLength is also attacker-influenced (a sleep of forged length).
Architectural significance — the forgery class has two surfaces. This is the first confirmed exploit on a direct publicVariable channel rather than the registered PVF dispatcher. The DR-1 remediation (validate the PVF command string before compile) does not protect direct channels like ATTACK_WAVE_INIT. So the economy/forgery owner decision must cover both: (1) the PVF dispatcher (DR-1, validated lookup) and (2) each direct publicVariableServer PVEH must re-derive trusted values server-side — here: take _side from the PV sender/owner, compute _supply from GetSideSupply _side on the server, and deduct the cost there — ignoring the payload's economic fields. Other direct channels (side-supply, supply-mission, MASH) share this surface and warrant the same treatment.
Handoff for Codex. Confirms backlog item attack-wave-authority (was new-from-2026-06-02-pv-scout) → confirmed, High; flip its status and cross-link DR-41 from Networking (direct-PV hazard table) and the economy-authority roadmap entry. Fold into the same owner decision as the economy class, with the explicit "two surfaces (PVF + direct PV)" note so the server-authority redesign covers direct channels too.
Outcome: Economy/forgery class extended to a new direct-PV channel (DR-41). Collaboration-follow pass: a Codex pv-scout candidate verified at source and promoted to a confirmed finding.
Lane hc-static-defense-verify (collaboration-follow: adjudicating two raw backlog candidates).
DR-42 — Static-defence HC delegation never reports created units back to the server (update-back commented out) — Low/Medium (headless/JIP; confirms hc-static-defense-sync)
The server delegates static-defence AI to a random headless client (Server/Functions/Server_DelegateAIStaticDefenceHeadless.sqf:26, ["…","HandleSpecial",['delegate-ai-static-defence',…]]). The HC receiver Client/Functions/Client_DelegateAIStaticDefence.sqf creates the units (:25 _retVal = … call WFBE_CO_FNC_CreateUnitForStaticDefence) — but the update-back to the server is commented out (:28 //["RequestSpecial", ["update-delegation-static_defence", _teams]] Call WFBE_CO_FNC_SendToServer;). By contrast, the town-AI delegation does report back: Client/Functions/Client_DelegateTownAI.sqf:35 sends ["RequestSpecial", ["update-town-delegation", _town, _town_vehicles]], which Server_HandleSpecial.sqf ("update-town-delegation") folds into the town's wfbe_active_vehicles. So static-defence units created on an HC are invisible to the server — there is no server-side record for cleanup, accounting, or re-delegation. The HC manages only its own group lifecycle locally (:30-38, a per-team while {count units > 0} {sleep 1}; deleteGroup). This compounds DR-21 (HC disconnect → server load-migrates the units but cannot re-delegate): for static defence the server doesn't even know the units exist. Owner decision: either un-comment/restore the update-back (define the server update-delegation-static_defence handler) or document that static-defence HC units are deliberately fire-and-forget. Confirms backlog hc-static-defense-sync.
The support-scout backlog candidate server-fps-hosted-loop-sleep ("move sleep outside the isDedicated branch in the server FPS monitor") is the same defect already confirmed as DR-19 (Round 9). Source re-verified: Server/Module/serverFPS/monitorServerFPS.sqf:1-7 is while {true} { if(isDedicated) { …; sleep 8; } } — on a hosted/listen server the if is false every iteration so the loop busy-spins with no yield (and Server/GUI/serverFpsGUI.sqf is the second, redundant publisher). Not a new finding — fold the backlog item into DR-19.
Handoff for Codex. Mark backlog hc-static-defense-sync → confirmed (DR-42); mark server-fps-hosted-loop-sleep → duplicate of DR-19. Cross-link DR-42 from the AI, headless and performance page near the DR-21 HC notes.
Outcome: two raw scout candidates adjudicated — one promoted (DR-42), one deduped (DR-19). AI/headless authority deepened.
Round 34 — 2026-06-02 (Claude) — external deep-research intake #2 (9 reports) → DR-43 (2 new source-confirmed leads)
Lane external-research-intake-2. Ray supplied 9 new deep-research reports (deep-research-report (1..9).md). Triaged all 9 (treating their content as untrusted leads, not authority — cross-checked at source). Same posture as the 3 PDFs in DR-26: these are downstream syntheses that corroborate the campaign, not independent source verification (they cite their own research-tool fetches, turnNNview…).
Mapping: (1) Runtime Architecture → boot/lifecycle DR-37 + the version.sqf lead below; (2) Trust-Boundary Audit → DR-1 (PVF Call Compile = privileged exec surface); (3) Feature Archaeology → DR-4/32/34/39 + the duplicate-binds lead below; (4) Modernization Strategy → roadmap (Codex lane); (5) Locality & JIP → DR-37/38; (6) Testing/Release Workflow → already shipped by Codex (Testing-Debugging-And-Release-Workflow.md); (7) Gameplay State Ownership → DR-32/38; (8) Server Authority Refactor → an independent restatement of the campaign's central thesis — "not one exploit but the architecture; funds/supply are mutated client-side then merely announced; the ledger is a replicated client mutation, not a server source of truth" = the economy-authority class (DR-6/14/16/22/23/27/28/41) + DR-1 + the two-surfaces point; (9) AI-onboarding playbook → agent-docs (Codex lane). Net: strong third-party corroboration; our source-cited DRs remain the verified core (superset-confirming-subset, as with DR-26).
DR-43 — two new leads extracted from the reports, both source-confirmed — Low (source-completeness + init redundancy)
(a) description.ext:39 #include "version.sqf" but version.sqf is absent from tracked source (original external-research note; refined below after a local ignored-file recheck). Since the live mission runs, the file must be present in generated/local/deploy context (consistent with the LoadoutManager/7za build per AGENTS.md). So this is a source-completeness/drift note, not a runtime bug: a clean checkout is not buildable/loadable directly from tracked source without the generation step that supplies version.sqf — anyone preprocessing description.ext from the raw tracked tree hits a missing include. Ties to the generated-mission story (DR-4/DR-32). Owner: commit a source version.sqf (or document and validate that packaging generates it).
2026-06-04 correction, refined: a later init/compile scout found Missions/[55-2hc]warfarev2_073v48co.chernarus/version.sqf:1 present on disk, but a stronger target-root recheck showed it is an ignored generated file, not tracked source: .gitignore:1 ignores it, git --literal-pathspecs ls-files -- Missions/[55-2hc]warfarev2_073v48co.chernarus/version.sqf returns no rows, and git status --ignored --short -- .../version.sqf reports !!. Vanilla Takistan has the same ignored-local-file shape via .gitignore:23. Keep the original clean-checkout release lesson: run/generate/check version.sqf for every target root before boot, pack or test claims.
(b) Server/Init/Init_Server.sqf has redundant duplicate compile/bind rows. Codex re-checked the current Chernarus source before promotion: three functions are live duplicate binds (WFBE_CO_FNC_LogGameEnd at :64 and :89, WFBE_SE_FNC_PlayerObjectsList at :69 and :91, WFBE_SE_FNC_AwardScorePlayer at :83 and :93), while three other apparent duplicates are commented remnants (WFBE_CO_FNC_InitAFKkickHandler, WFBE_CO_FNC_monitorServerFPS, WFBE_SE_FNC_MASH_MARKER). The live duplicates are perf-trivial because they happen at init and bind the same files, but they are a maintenance trap: if a pair diverges later, the second bind silently wins. The LogGameEnd duplicate also sits near the DR-13 game-end cleanup area. Owner: de-duplicate live binds and either remove or clearly annotate the commented remnants.
Handoff for Codex. Add the 9 reports to external-research-report-manifest.json (Codex's lane); mark them corroborating (no contradictions found). The two confirmed leads (version.sqf source gap; duplicate Init_Server binds) are small code-owner cleanups — cross-link DR-43(b) from the victory/DR-13 area and DR-43(a) from the tooling/generated-mission docs.
Outcome: external-research intake #2 complete — 9 reports corroborate DR-1..DR-42 (esp. report 8 ↔ the economy-authority thesis); two new source-confirmed leads recorded as DR-43.
Round 35 — 2026-06-02 (Claude) — side-supply ledger is directly client-writable (DR-44); 2nd direct-PV forgery
Lane direct-pv-supply-authority (research autonomy: walking the direct publicVariableServer channels enumerated in Public variable channel index for the forgery class DR-41 opened).
DR-44 — wfbe_supply_temp_<side> lets any client write a side's supply balance via a forged direct PV — High (economy authority / forgery)
Chain (source-cited):
-
Client sender
Common/Functions/Common_ChangeSideSupply.sqf:28-30:missionNamespace setVariable [format ["wfbe_supply_temp_%1", _side], [_side, _amount, _reason]]; publicVariableServer format ["wfbe_supply_temp_%1", _side];— a direct channel (not via the PVF dispatcher). -
Server handler
Server/Functions/Server_ChangeSideSupply.sqf(addPublicVariableEventHandleronwfbe_supply_temp_west:1andwfbe_supply_temp_east:25): takes_side = _this select 1 select 0and_amount = _this select 1 select 1straight from the payload (:4-5/:28-29), computes_change = _currentSupply + _amount(:11/:35), caps atWFBE_C_MAX_ECONOMY_SUPPLY_LIMIT, thenmissionNamespace setVariable ["wfbe_supply_<side>", _change]+publicVariable(:19-21/:43-45). -
No authority: the handler never checks the PV sender, never verifies
_sidebelongs to the sender, and never re-derives_amountserver-side. So a forgedwfbe_supply_temp_west = [west, 999999, "x"]makes the server set west's supply to (current + 999999), capped at the max — arbitrary side-supply inflation from any client.
Impact. Supply gates attack-wave eligibility (≥25000, DR-41), funds/income, and production — so writing the supply balance is a high-leverage economy exploit. The author was aware: the _reason fallback string is literally "This might indicate a malicious supply update request. Check stuff if you see this message." (:6/:30) — i.e. a log breadcrumb was added instead of authority validation.
Relationship to other findings. Same files as DR-22 but a different axis: DR-22 is the broken overspend floor (if (_change<0) then {_change=_currentSupply-_amount} should be {_change=0}, a correctness bug present here too at :12/:36); DR-44 is the authority/forgery gap (payload-trusted _amount, no sender/side check). And it is the second confirmed direct-PV forgery after DR-41 — establishing that the direct-channel surface is a class, not a one-off. Sharpens the economy thesis: not only is spending client-authoritative (DR-6/14/16/22/23/27/28), the supply ledger itself is directly client-writable.
Owner decision. Folds into the economy-authority decision (server-side authority vs BattlEye) with the two-surfaces note (PVF dispatcher DR-1 + direct channels DR-41/DR-44). The direct fix: the wfbe_supply_temp_<side> handler must derive the authorized delta server-side (or validate the sender is the side's commander/server) and ignore the payload's _amount as an authority. BattlEye publicvariable.txt should also restrict wfbe_supply_temp_* (not shipped, DR-30).
Handoff for Codex. Update the Public variable channel index wfbe_supply_temp_* row to cite DR-44; add DR-44 to the economy-authority class wherever the class is listed (it's a new member); the Pending owner decisions economy table gains a row.
Outcome: direct-PV forgery surface now has two confirmed members (DR-41 attack-wave, DR-44 side-supply); economy thesis extended to "the supply balance is client-writable".
Round 36 — 2026-06-02 (Claude) — full wiki audit follow-through: DR-45 (town-AI vehicle despawn) + direct-PV surface closed + coverage-gap assessment
Lane wiki-audit-followthrough. Three parallel audits of all 60 wiki pages (duplication already resolved by Codex; this pass = accuracy/consistency/coverage). The wiki is healthy (no broken links, no orphans, DR severities consistent everywhere). The Public-Variable-Channel-Index PVF line ranges (:8-20/:23-37) were a verified audit false positive and should not be "fixed." Correction 2026-06-03: this paragraph formerly grouped DR-15's _side = _this at Server_AssignNewCommander.sqf:3 into that false-positive bucket; source recheck confirms that was stale. RequestNewCommander.sqf:13 still passes [_side, _assigned_commander], while Server_AssignNewCommander.sqf:3-5 treats the full payload as _side and indexes element 1 as commander, so DR-15 remains patch-ready/source-unpatched. Real outcomes below. Update 2026-06-07: DR-15's call-shape bug is now fixed on master (Server_AssignNewCommander.sqf:4 reads _side = _this select 0;) — see the RESOLVED note on the DR-15 record; only the redundant new-commander-assigned broadcast remains.
DR-45 — Town-AI inactivity despawn deletes vehicles with player passengers — Medium (gameplay; player vehicle loss)
Server/FSM/server_town_ai.sqf:213-216 cleans up a captured/inactive town's vehicles:
{ if (alive _x) then { if (!(isPlayer leader group _x)) then {deleteVehicle _x} } } forEach (_town getVariable 'wfbe_active_vehicles');
The guard !(isPlayer leader group _x) only spares a vehicle whose group leader is a player. It does not inspect crew/cargo/turret occupants, so an AI-led (or empty-group) vehicle that a player is riding as a passenger/cargo is deleted under them during the despawn sweep. Promotes the existing (un-numbered) Town-AI-Vehicle-Despawn-Safety playbook — confirmed by Codex's Einstein verifier and now re-confirmed at source — to a formal DR. Fix: before delete, also check crew _x / assignedCargo _x for any isPlayer, or skip vehicles with any player occupant.
Following DR-41/DR-44, the remaining client-touchable direct publicVariable channels were source-checked for the same forgery class:
-
REQUEST_SUPPLY_VALUE(Server/Functions/Server_PV_RequestSupplyValue.sqf) — clean: a read-only query (SUPPLY_VALUE_REQUESTED = (side _player) call GetSideSupply; (owner _player) publicVariableClient …); no mutation, no authority surface (worst case: a client reads another side's public supply — negligible). -
MARKER_CREATION(Client/Functions/Client_onEventHandler_MARKER_CREATION.sqf) — clean/cosmetic: creates a side-visible local map marker from the payload; worst case is cosmetic marker spam, no gameplay/authority impact.
Conclusion: the direct-PV forgery surface is fully enumerated and bounded to the two mutation channels (DR-41 ATTACK_WAVE_INIT, DR-44 wfbe_supply_temp_<side>); the read/cosmetic direct channels are safe. No further direct-PV forgery findings.
CLEARED 2026-06-07 (Round 41, agent team). Every item below has now been source-reviewed to finding depth; the residual list is empty. See Round 41 for DR-51..DR-54 and the dead-code/correction routing.
Original accounting (kept for provenance), now annotated with its clearance:
-
Server/AI respawn + orders — ✅ CLEARED (Round 41): DR-51 (both respawn paths orphaned/uncalled), AI_TLWPHandler dead, live water-loop traced to
Common_WaypointPatrolTown.sqf(not the deadOrders/AI_Patrol.sqf). -
Cleaners/restorers Perf (
Server/FSM/cleaners/*,buildings_restorer.sqf) — already documented in Marker cleanup/restoration atlas. Live RPT samples remain a code/test-owner perf-tuning gate (not a review gap). -
Config data model (
Common/Config/Core*/,Gear/,Loadout/,Defenses/) — ✅ CLEARED (Round 41): full load-order/data-model map produced and folded into Assets/config atlas; DR-54 (Core_US/USMC dedup guard + AH64D faction). -
Server/FSM/basearea.sqf,groupsMonitor.sqf,Server/Support/Support_*— ✅ CLEARED (Round 41): DR-52 (support-special authority), groupsMonitor dead-code, basearea_onAreaRemovedaccumulation (nuanced perf). -
PR#1 supply-helicopter delta — ✅ CLEARED (Round 41): line-by-line on
feat/supply-helicopter→ DR-53 (forgeable SupplyAmount + non-cash double-reward); the suspected stackedKilledEH was refuted. - Code depth note (updated 2026-06-07): the AI/respawn, config, support and PR #1 subsystems are now at finding depth alongside the economy/forgery and PVF classes. The only remaining non-review gaps are owner decisions and live RPT/Arma smoke evidence.
Handoff for Codex. Audit punch-list (Codex-lane accuracy fixes) recorded in Wiki quality audit "Round 2"; DR-45 should be cross-linked from the Town-AI playbook + AI/headless atlas; the coverage-gap list seeds the next review queue.
Outcome: DR-45 filed (town-AI passenger-vehicle deletion); direct-PV forgery surface closed as bounded; coverage gaps enumerated for the next phase.
Lane send-message-rce-review. While producing a standalone "20 improvements" review for the owner (a shareable PDF), a fresh source pass over the message/notification path surfaced a second network-data call compile site that DR-1's analysis explicitly assumed did not exist.
DR-46 — SEND_MESSAGE broadcast call compiles network text: a second client-side RCE, independent of the PVF dispatcher — High (security / RCE; extends and corrects DR-1)
Client/Functions/Client_onEventHandler_SEND_MESSAGE.sqf:25-31 handles the SEND_MESSAGE direct publicVariable broadcast (_SEND_MESSAGE_infos = _this select 1; index 0 = text, index 2 = receiving side, index 3 = multi-language flag). When the flag is true it runs:
if _is_multi_language_message then { _messageText = call compile _messageText };
systemChat _messageText;
_messageText is network data. Any connected client can broadcast SEND_MESSAGE with arbitrary SQF in index 0 and true in index 3; every receiver whose playerSide matches index 2 compiles and executes the payload — a full client-side remote-code-execution primitive. It does not pass through WFBE_PVF_* / Server_HandlePVF / Client_HandlePVF, so even a perfect DR-1 dispatcher fix leaves this surface open. Common/Functions/Common_SendMessage.sqf:26 has the identical sender-local call compile, and the callers (artillery / ICBM friendly+enemy messages) pass compilable strings.
Correction to DR-1. DR-1's "why the dispatch never needs Call Compile" note (≈ line 159) states the other call compile sites "compile files… or local engine key-strings…, not network data" and that there is "no second-order injection on the PVF path." That is accurate for the PVF path, but SEND_MESSAGE is a direct addPublicVariableEventHandler outside that path, and it does compile network data. The repo therefore has two independent network-data call compile RCE surfaces, not one — DR-1's single-site assumption should be amended to name SEND_MESSAGE explicitly.
Fix. Treat the multi-language payload as a stringtable key plus arguments — ["STR_KEY", arg1, …] — and resolve with localize + format; treat any non-array payload as a literal string and never compile it. Patch the identical line in Common_SendMessage.sqf and update the artillery/ICBM callers to send arrays. Optionally allowlist the SEND_MESSAGE channel (with a value-shape filter) in the BattlEye publicvariable.txt from DR-30. Source-verified; fix shape in agent-hardening-backlog.jsonl#send-message-call-compile-rce.
Maintainability leads (for Codex to verify against existing pages, not yet filed as DRs). The same pass source-confirmed these, but they may already be owned by Variable and naming conventions / SQF atlas: (1) Common/Init/Init_Common.sqf compiles ~15 functions twice — once as a short global (GetSideID) and again as WFBE_CO_FNC_GetSideID, both pointing at the same file (plus ~22 un-prefixed globals in Init_Server.sqf and four GetClosestEntity{,2,3,4} variants); (2) the four Client_Support{Repair,Refuel,Rearm,Heal}.sqf (~90% identical), Construction_{Small,Medium}Site.sqf (identical heads) and the ten Common/Config/Loadout/*.sqf (one structure, data-only difference) are large copy-paste families; (3) ~12 hardcoded English hint/systemChat strings bypass stringtable.xml.
Codex closure. Cross-linking is complete: DR-46 is routed from Networking and public variables, Public variable channel index, SQF atlas, Feature status, Pending owner decisions and Hardening roadmap. The DR-1 single-site note above now explicitly scopes "no second-order injection" to the PVF path and names SEND_MESSAGE as the second network-data compile surface. The maintainability leads remain verify-then-document, not new DRs unless confirmed undocumented.
Outcome: DR-46 filed and Codex cross-link closure completed — a second, source-verified network-data call compile RCE (SEND_MESSAGE), correcting DR-1's single-site assumption. The source patch remains P0 patch-ready/source-unpatched in agent-hardening-backlog.jsonl. (Context: produced alongside a standalone 20-improvement PDF for the owner.)
DR-30 correction — remoteexec.txt is Arma 3-only; BattlEye filters are local + contingent (defense-in-depth, not the primary fix)
Two refinements to DR-30 (BattlEye posture), surfaced during the improvements pass and confirmed at source:
-
remoteexec.txtdoes not apply to Arma 2 OA. It is an Arma 3 BattlEye filter (it gates the A3-onlyremoteExec/remoteExecCallcommands); Arma 2 OA has no such command, so there is nothing for it to filter. DR-30 / External-Integrations and any "missing filters" list should dropremoteexec.txtand name the A2 OA set instead:scripts.txt,publicvariable.txt,createvehicle.txt,setpos.txt,setdamage.txt,setvariable.txt,deletevehicle.txt,mpeventhandler.txt,addmagazinecargo.txt/addweaponcargo.txt/addbackpackcargo.txt,teamswitch.txt,waypointcondition.txt,selectplayer.txt,attachto.txt. -
BattlEye is defense-in-depth, contingent on the server still loading BE. BE's global/online anti-cheat for the Arma 2 series is effectively defunct, but the filter files are processed locally by the server-side BE component (reads
BEpathnext toserver.cfg), independent of BE's online services. Direct evidence the deployment model assumes working BE filters:Client/FSM/updateclient.sqf:153-162broadcastskickAFKwith the comment "detected by BattlEye (customized filter)… Must be kicked using BattlEye Filter." So if AFK-kick works on the production server, BE filters are live (and ascripts.txtwould too); if it does not, BE isn't loaded and the BattlEye remediation is moot. Either way, the durable, BE-independent fix for the RCE/economy classes is server-side authority (DR-1, DR-46, DR-6, DR-27, DR-41/44); BattlEye is a layered backstop only.
Codex closure. External-Integrations and this DR-30 list now drop remoteexec.txt from the missing Arma 2 OA filter framing, name the OA-era filter set and reframe BattlEye as contingent local-filter defense in depth using updateclient.sqf:153-162. DR-30's substance — no security filters are shipped in the repo — stands; only the filter-name list and the "primary mitigation" framing changed.
Lane commander-vote-ai-no-commander-outcome-mismatch. A source pass over the commander election worker found a server/client disagreement around AI/no-commander votes.
DR-47 — Commander vote selects any non-tied player candidate even when AI/no-commander votes should win — Medium (gameplay correctness / commander control)
Server/Functions/Server_VoteForCommander.sqf:24-29 counts player-team votes and treats wfbe_vote == -1 as _aiVotes. The final selection then uses:
if ((!_tie && _highest >= _aiVotes && _highestTeam != -1) || (!_tie && _highest <= _aiVotes && _highestTeam != -1)) then {_commander = _teams select _highestTeam};For numeric vote counts, _highest >= _aiVotes or _highest <= _aiVotes is always true. Therefore any non-tied player candidate with _highestTeam != -1 becomes commander, including equal-vote and AI/no-commander-majority cases. The AI/no-commander fallback only remains reachable for ties, no player candidate, or the later "selected team is not player-led" guard at :45-46.
The client vote dialog presents different semantics: Client/GUI/GUI_VoteMenu.sqf:87-89 previews AI/no commander when the highest row is row 0 or when the leading option is not above half of counted player voters. That means clients can see "AI"/"No Commander" as the apparent outcome while the server assigns a player commander after the countdown.
Fix shape. Decide the intended rule first: plurality, strict majority, AI/no-commander as a real candidate, or no-commander only on row-0 win. Patch the server condition to match that rule, then smoke player-majority, no-commander-majority, equal-vote, player tie and late-join/revote restart cases. Keep this separate from DR-15 manual reassignment call shape and commander-authority hardening, though they share the same UX surface.
Codex closure. Cross-linked from Feature status and Commander/HQ lifecycle atlas. Source remains unpatched.
Round 39 — Town-defense overhaul capture-persistence cleanup re-introduces the occupancy-deletion class (Claude, 2026-06-07)
Lane town-defense-overhaul-capture-persistence-occupancy-review. The Marty_town_defense_overhaul merge landed on stable/local master 89ae9dad after the 2026-06-02 coverage milestone, adding three new files (Common/Functions/Common_MarkTownDefenseAsset.sqf, Server/Functions/Server_CleanupExpiredTownDefenseAssets.sqf, Server/Functions/Server_SendTownDebugChat.sqf) plus 17 modified files in Chernarus. This is freshly-landed, previously-unreviewed code, so it was source-reviewed for the DR-45 hazard class and new authority/perf surfaces.
DR-48 — Town-defense capture-persistence cleanup deletes occupied captured vehicles; OBJECT guard is occupancy-blind and the GROUP branch is unguarded — Medium (gameplay; player vehicle loss, extends DR-45)
When a town is captured, its surviving defender groups, units and vehicles are registered for temporary persistence and given an expiry:
// Server/FSM/server_town.sqf:238-258
_persistDelay = missionNamespace getVariable ["WFBE_C_TOWN_DEFENSE_CAPTURE_PERSIST_TIME", 600];
if (WF_Debug) then {_persistDelay = 60};
_persistUntil = time + _persistDelay;
...
{ ... [_location, _x, _sideID, "captured_mobile_vehicle", _persistUntil] Call WFBE_CO_FNC_MarkTownDefenseAsset; ... } forEach _captureVehicles;
WFBE_SE_FNC_CleanupExpiredTownDefenseAssets runs per town, every town-AI loop iteration, before the activity checks (Server/FSM/server_town_ai.sqf:61), so expired assets are reaped even in an actively-contested just-captured town — exactly when a capturing player is most likely riding a captured vehicle. The OBJECT delete branch is:
// Server/Functions/Server_CleanupExpiredTownDefenseAssets.sqf:61-64
if (_assetType == "OBJECT") then {
if !(isPlayer _asset) then {
if !(isPlayer leader group _asset) then {deleteVehicle _asset};
};
};
Two distinct gaps, both source-confirmed:
-
The OBJECT guard is occupancy-blind for vehicles.
captured_mobile_vehicleandstatic_weaponassets are vehicle objects, and the guard never inspectscrew/cargo/turret occupants — it is the same class as DR-45. Worse, for a vehicle objectgroup _assetisgrpNull(group resolves a person, not a vehicle), soisPlayer leader group _assetevaluatesisPlayer objNull = falseand the delete always fires. Under that engine semantics the guard spares no occupant — not even a player driver — so a player who boarded a captured town vehicle has it deleted under them when the 10-minute persistence (60s underWF_Debug) expires. The repo's own occupancy primitive corroborates this:Server/Functions/Server_HandleEmptyVehicle.sqfkeeps a vehicle alive while{alive _x} count crew _vehicle > 0, i.e. it usescrew, nevergroup, to detect occupants. Open verification: the BIKI page forgroupcould not be fetched live this pass (HTTP 403); confirm in-engine thatgroup <vehicle>returnsgrpNullin Arma 2 OA 1.64. The recommended fix below is correct under either interpretation. -
The GROUP branch has no player guard at all.
static_group/captured_static_group/mobile_groupassets hit the GROUP branch, which deletes every member unconditionally:// Server/Functions/Server_CleanupExpiredTownDefenseAssets.sqf:57-60 if (_assetType == "GROUP") then { {deleteVehicle _x} forEach units _asset; deleteGroup _asset; };Real-world player risk here is lower (town-defender groups are AI-created), but the asymmetry — OBJECT branch attempts a (broken) player guard while GROUP branch attempts none — is a latent gap if a player ever ends up in a marked group (e.g. team-switch/join into a defender group).
Relationship to DR-45. DR-45 is the same occupancy-deletion class in the inactivity despawn path (server_town_ai.sqf:278); DR-48 is the capture-persistence path in the new overhaul, with distinct files and asset types, so it is filed separately. The group <vehicle> = grpNull observation, if confirmed, also sharpens DR-45: its :278 guard !(isPlayer leader group _x) likewise iterates vehicle objects from wfbe_active_vehicles, so it too would spare no occupant rather than only "missing cargo/passengers." Both fixes converge on the same crew-based primitive.
Fix shape. Before deleting an OBJECT asset, skip it if any occupant is a player: if (({isPlayer _x} count crew _asset) == 0) then {deleteVehicle _asset}; (optionally retain the existing leader exception as a behavior-preserving addition, matching the DR-45 patch shape on Town-AI vehicle despawn safety). For the GROUP branch, skip member deletion when any unit is a player: if (({isPlayer _x} count units _asset) == 0) then { {deleteVehicle _x} forEach units _asset; deleteGroup _asset; };. Patch Chernarus source, propagate to maintained Vanilla via LoadoutManager, then smoke: capture a town, board a captured_mobile_vehicle as driver and as cargo, and confirm it is not deleted under the player at expiry; verify empty captured vehicles are still reaped. Fix shape in agent-hardening-backlog.jsonl #town-defense-overhaul-capture-persistence-occupancy.
Branch scope. Source-verified on current source/Vanilla and stable/Miksuu 89ae9dad. The overhaul is not present on historical 2cdf5fb8; perf/quick-wins 0076040f and release 7ff18c49 predate this merge for these new files — branch presence of the overhaul on those heads should be confirmed by the next current-head refresh pass before cross-branch status wording.
Outcome: DR-48 filed — the new town-defense overhaul re-introduces the DR-45 occupancy-deletion class in the capture-persistence cleanup, with an occupancy-blind OBJECT guard (illusory for vehicles, pending one in-engine confirmation) and an unguarded GROUP branch. Source unpatched; routed to the Town-AI playbook, coverage ledger and hardening backlog.
Lane audit-findings-queue-verification-sweep. The Audit Findings Queue (2026-06-03) held ~48 previously-UNVERIFIED (⬜) audit claims flagged as "claims to check." This sweep source-checked every remaining row against current master (Chernarus) via read-only scouts, then adversarially re-verified the high-severity promotions at source. The queue page now carries the per-row verdicts; this round records the two genuinely-new confirmed exploits as numbered findings plus one correction.
DR-49 — Side-supply underflow guard adds supply instead of clamping (economy exploit) — High (economy integrity)
Common/Functions/Common_ChangeSideSupply.sqf:24-25 and the server-side handlers Server/Functions/Server_ChangeSideSupply.sqf:12 (west) / :36 (east):
_change = _currentSupply + _amount;
if (_change < 0) then {_change = _currentSupply - _amount};
The second line is intended as an underflow guard, but for a negative _amount (a deduction), _currentSupply - _amount = _currentSupply + |_amount|. So any deduction large enough to drive supply below zero instead increases side supply by the deduction's magnitude. The correct clamp is _change = 0. This is the arithmetic logic of the supply mutation itself — distinct from DR-44, which covered the forgeability of the wfbe_supply_temp_<side> channel; DR-49 is wrong even for legitimate server-issued deductions. Fix: if (_change < 0) then {_change = 0}; in all three sites (Common + both server handlers); propagate to maintained Vanilla. Smoke: drive a side's supply near zero and issue a deduction larger than the balance; confirm it clamps to 0, not jumps up. Fix shape in agent-hardening-backlog.jsonl #side-supply-underflow-guard-inverts. (Was audit row SG3.)
DR-50 — HQ kill awards score twice on a clean kill and once on a teamkill — Medium (scoring integrity)
Server/Functions/Server_OnHQKilled.sqf awards HQ-kill score in two places:
-
:23,46-47— unconditional_points = 30000 / 100 * WFBE_C_BUILDINGS_SCORE_COEF(900 at the default coef 3), awarded toleader _killer_groupon every HQ kill, including teamkills; -
:74-81— a second award_score = 900toleader _killerGroup, this one correctly guarded byif (_side != side _killer)(non-teamkill only).
Net effect: a legitimate enemy HQ kill awards 1800 (900 + 900); a teamkill still awards 900 from the unconditional block, despite the :62-71 message branch treating teamkills as punishable. Fix: move the :46-47 award inside the non-teamkill guard (or delete one of the two awards so a clean kill pays once), and ensure teamkills award nothing. Smoke: kill an enemy HQ and confirm a single bounty; teamkill a friendly HQ and confirm zero score. Fix shape in agent-hardening-backlog.jsonl #hq-kill-double-score. (Was audit row SG2.)
The audit row NJ10 (Client/Init/Init_Client.sqf:512, "JIP HQ killed-EH not added when deployed → victory may not fire") was flagged "high." Source re-verification shows the authoritative HQ-killed handler is server-local — Server/Init/Init_Server.sqf:323, Server/Construction/Construction_HQSite.sqf:89 (comment: "Killed EH fires localy, this is the server") and Server/Functions/Server_MHQRepair.sqf:37 all add killed → WFBE_SE_FNC_OnHQKilled directly on the server. The client EH at Init_Client.sqf:515 only relays process-killed-hq to the server (redundant with the server's own EH). The !_isDeployed gate means a post-deploy JIP client skips the redundant relay, but the server still processes the kill and fires victory. NJ10 is therefore a minor robustness/cleanup item (⚠️ NUANCED), not a victory failure. Recorded so future agents don't re-open it as critical.
Outcome: The Audit Findings Queue is fully verified — no ⬜ rows remain. Two new source-confirmed exploits filed (DR-49 supply underflow, DR-50 HQ double-score); SG1 re-confirms DR-11/DR-13 and SG14 maps to DR-30; NJ10's "victory-blocker" framing corrected. Per-row verdicts, false positives (V8, V9, V12, NJ6), GONE/fixed (AI13) and nuanced/design items live on the Audit Findings Queue.
Lane clear-wiki-coverage-gap-backlog. A five-agent team source-reviewed the weakly-understood subsystems listed in Round 36's coverage-gap assessment (AI respawn, AI orders/waypoints, the config data model, server support + misc FSM, and the PR #1 supply-helicopter branch); every candidate finding was then adversarially verified at source by a second agent. This round records the confirmed findings and two important corrections; the gap list above is now marked cleared.
DR-51 — AI respawn handlers are orphaned: the active respawn path never attaches, so AI leaders silently never respawn — Medium (gameplay; AI never regenerates)
Server/AI/AI_AddMultiplayerRespawnEH.sqf is the only file that attaches the MPRespawn handler driving AIAdvancedRespawn (the non-vanilla/OA path), but it has no call site — a whole-tree grep for AI_AddMultiplayerRespawnEH, AddMultiplayerRespawnEH and addMPEventHandler returns zero hits outside the file itself. AIAdvancedRespawn is compiled at Server/Init/Init_Server.sqf:12 but only ever referenced inside that orphaned EH body, so it is dead. The vanilla path AISquadRespawn (Init_Server.sqf:11) is gated by WF_A2_Vanilla, which initJIPCompatible.sqf:91 sets false unconditionally (the only true path is #ifdef VANILLA, and VANILLA is never defined), and a grep for spawn AISquadRespawn returns nothing — so it never runs either. Net: both server AI-respawn paths are compiled-but-uncalled; AI group leaders are never re-spawned by this subsystem on a dedicated server. Fix: compile AI_AddMultiplayerRespawnEH.sqf and call it for each AI group leader at group creation (matching the WF_A2_Vanilla guard), or delete the dead path if AI leader respawn is intentionally disabled. Source-verified on current master; Arma smoke (kill an AI leader, confirm no respawn) recommended before patch. (From the AI-respawn review.)
DR-52 — Support-special spawn requests have no server-side authorization, and accept a client-supplied group handle — High (authority; free support assets + cross-team injection)
The support-special request chain is Client GUI → WFBE_PVF_RequestSpecial → Server_HandlePVF → RequestSpecial.sqf:1 (\_this Spawn HandleSpecial`) → Server_HandleSpecial.sqfcasesParatroops/ParaVehi/ParaAmmo/uav (:43-65), each of which does only args spawn KAT*with **no commander check, no side verification, and no server-side funds deduction** (funds are deducted client-side inGUI_Menu_Tactical.sqf:372,514,525, and the GUI only gates the commander check for ICBM, not these four). The PVEH registration (Init_PublicVariables.sqf:50) extracts no sender identity. Worse, the support scripts read the **owning group from the client payload** — Support_Paratroopers.sqf:5 (_playerTeam = _this select 3), Support_ParaAmmo.sqf:7, Support_ParaVehicles.sqf:7, Support_UAV.sqf:9— with no check thatside _playerTeam == _sideor that the group belongs to the sender, so a forged request cancreateUnit-join paratroopers into an arbitrary (enemy) group and route server→client marker messages to the enemy leader. The PVF dispatcher's Call Compileonly resolves theSRVFNC-prefixed name, so this is a **data-authority** hole, not RCE — it shares the client-authoritative class with DR-1/DR-6/DR-27/DR-28/DR-41/DR-44. **Fix:** in HandleSpecial, derive the sender's side/group/commander-status from the PVEH sender identity (_this select 0), validate against the payload, and deduct funds server-side. Source-verified on current master`. (From the server-support review.)
DR-53 — PR #1 supply-helicopter economy is client-forgeable and double-pays the pilot on non-cash heli runs — High (economy; branch feat/supply-helicopter)
On origin/feat/supply-helicopter: the client sets SupplyAmount / SupplyByHeli as broadcast object variables on the supply vehicle (Client/Module/supplyMission/supplyMissionStart.sqf:53-55, setVariable [...,true]), and the server reads them back without re-derivation — supplyMissionStarted.sqf:6 (_byHeli) and supplyMissionCompleted.sqf:9 (_supplyAmount), which is then paid via ChangeSideSupply (:38). Any client can setVariable ["SupplyAmount", <arbitrary>, true] on the vehicle and the server pays it out (capped only by the global WFBE_C_MAX_ECONOMY_SUPPLY_LIMIT, not per-mission). Separately, for non-cash heli runs (Air level 3): the server deposits the full _supplyAmount into the team pool via ChangeSideSupply and the client pays the pilot _supplyAmount * WFBE_C_SUPPLY_HELI_REWARD_MULT personal cash via ChangePlayerFunds (supplyMissionCompletedMessage.sqf:19) with no _cashRun guard — value is minted from both paths. (Air-4 cash runs skip ChangeSideSupply and are single-source/clean.) Fix: re-derive _supplyAmount server-side from the source town's supplyValue and re-check Air upgrade; gate the client pilot reward on _cashRun, or pay all rewards server-side. Branch-scoped to feat/supply-helicopter; must be resolved before PR #1 merge + Arma smoke. (From the PR #1 review.)
DR-54 — Core_US.sqf / Core_USMC.sqf unit-registration dedup guard is broken, and AH64D_EP1 is mislabeled to the wrong faction — Low (config correctness / buy-menu filter)
In Common/Config/Core/Core_US.sqf:289 and Core_USMC.sqf:239 the duplicate-detection read drops the _get = assignment (missionNamespace getVariable (_c select _z); with the result discarded), so _get stays nil every iteration and the isNil '_get' guard is always true — the duplicate-registration log branch is unreachable and every entry unconditionally overwrites any prior registration. The other 19 Core/*.sqf files use the correct _get = … form. Compounding this, Core_US.sqf:205-206 registers AH64D_EP1 with faction field (index 8, QUERYUNITFACTION) 'USMC' instead of 'US', so the buy-menu filter (Client_UIFillListBuyUnits.sqf:39) shows it only under the USMC tab, not US. Fix: restore _get = on both lines; correct the AH64D_EP1 faction string (or move the entry to Core_USMC.sqf). Source-verified on current master. (From the config-data-model review.)
-
Server/AI/AI_TLWPHandler.sqs(legacy straggler-sync SQS) andServer/FSM/groupsMonitor.sqf(debug poll, launch commented atInit_Server.sqf:571) are dead code — no call site anywhere. Routed to Dead/stale code register. -
AI autonomous supply-truck is dead:
Init_Server.sqf:387does[_side] Spawn UpdateSupplyTruckbut the only compile ofUpdateSupplyTruckis commented at:36, so it spawnsnil; andAI_UpdateSupplyTruck.sqf:17ExecFSM "Server\FSM\supplytruck.fsm"references a file that does not exist anywhere in the tree. This confirms and sharpens the existing AI supply-truck branch matrix (nil-Spawn site:387is the precise current-source symptom). -
Live unbounded water-avoidance loop: the audit's AI11/AI_Patrol water-loop lead is real but the dead files are
Orders/AI_Patrol.sqf/AI_TownPatrol.sqf(compiled-but-uncalled); the live instance isCommon/Functions/Common_WaypointPatrolTown.sqf:48-52(andCommon_WaypointPatrol.sqf), invoked fromserver_town_patrol.sqf:43. AsurfaceIsWaterspin with no iteration cap can starve its scheduler thread near water-adjacent towns. Perf-owner lane. -
Config init file-read cost: each
Core/*.sqfvehicle entry with crew-slot-2doesCall Compile preprocessFileof the crew-slot helper (which itself recurses into two morepreprocessFilehelpers) — ~281 such entries across 21 Core files → ~850-1000+ synchronous file reads at startup. One-shot init cost; hoist the compile out of the loop if startup time matters. -
PR #1 branch carry-over:
server_town_patrol.sqf:18onfeat/supply-helicopterflips the loop exit to||(while {!WFBE_GameOver || _aliveTeam}), leaking one zombie patrol thread per town-team after game-over (30 s sleep, so not a spin). Fix to&&before merge.
-
PR #1 "stacked
KilledEH" is REFUTED. The long-suspected duplicate-interdiction-handler-on-reload issue does not occur:supplyMissionStarted.sqf:13-16guards the add withisNil {getVariable "wfbe_supply_killed_eh_set"}and broadcasts the flag, so a second load on the same vehicle never re-adds the EH. The real residual issue is a double cooldown timer (supplyMissionStart.sqf:6-9reads the cooldown before the server PV round-trip returns) plusSupplyAmount/SupplyFromTownnot being zeroed on abort — Medium, not the suspected High EH-stack. -
PR #1 interdiction
KilledEH is server-safe. A candidate "EH runsChangeSideSupplyon a client" was refuted:ChangeSideSupply→Common_ChangeSideSupply.sqf:30onlypublicVariableServerswfbe_supply_temp_<side>; the economy write happens exclusively in the server-onlyServer_ChangeSideSupplyPVEH. (The separate forgeability ofwfbe_supply_temp_*is the already-filed DR-44, not this path.) -
AI loadout empty-array crash is a non-issue (audit AI14 follow-up): every
WFBE_%1_AI_Loadout_*across all 10 faction roots is non-empty andCommon_EquipUnit.sqf:18-19guards the optional 4th/5th args withcount _this > 4/5, so neither therandom count []nor the EquipUnit else-branch is reachable. The literal13index equalsWFBE_UP_GEAR(correct).
Outcome: the coverage-gap backlog is cleared — all five weakly-understood subsystems are now source-reviewed to finding depth. DR-51..DR-54 filed; dead code and config bugs routed; two PR #1 assumptions corrected (Killed-EH no-stack; interdiction EH server-safe). Full per-subsystem maps, source anchors and open questions were produced by the agent team and are summarized on the owner pages (AI/headless, Support specials, Assets/config atlas, Current supply heli PR).
Round 42 — Deeper hazard-class sweep (68-agent team) → DR-55..DR-57 + systemic authority result (Claude, 2026-06-07)
Lane deep-hazard-class-sweep. An orthogonal pass: 7 agents swept the whole mission tree by hazard class (exhaustive PV/PVF authority enumeration, direct-channel forgery, call-compile/EH-stacking, JIP/HC missing-broadcast, perf busy-waits, logic inversions, whole-tree dead-code), each feeding adversarial verifiers, deduped against DR-1..DR-54 and the audit-queue confirmations. The headline is systemic.
DR-55 — The PVF / PVEH / direct-publicVariable handler surface systemically lacks server-side sender authentication — Critical (authority; the economy/forgery class is the whole network surface, not a few channels)
Root cause: the dispatcher Server/Functions/Server_HandlePVF.sqf:14 runs _parameters Spawn (Call Compile _script) and Common/Init/Init_PublicVariables.sqf:50 registers … addPublicVariableEventHandler {(_this select 1) Spawn WFBE_SE_FNC_HandlePVF} — the sender's machine/identity (_this select 0/select 2) is never extracted or forwarded. So every server PVF handler and direct-PV EH that does not independently re-derive the sender's side/role from its own payload is forgeable by any connected client (including the enemy side). This generalizes DR-1 (RCE), DR-27, DR-41, DR-44, DR-52, DR-53 from "specific channels" to "the entire surface." Newly enumerated forgeable handlers (all source-verified, none previously catalogued):
| Handler / channel | Source | Severity | Forged effect |
|---|---|---|---|
RequestVehicleLock |
Server/PVFunctions/RequestVehicleLock.sqf:1-7 |
Critical | lock/unlock any vehicle (incl. enemy MHQ) — _vehicle lock _locked with no side/owner check |
RequestChangeScore |
Server/PVFunctions/RequestChangeScore.sqf:3-8 |
Critical | set any player's score to an arbitrary value (addScore -_old; addScore _new) |
ATTACK_WAVE_DETAILS (direct PV) |
Server/PVFunctions/AttackWave.sqf:19-42 |
Critical | drain a side's entire supply to 0 + set arbitrary price modifier (e.g. 0.01) for arbitrary duration; distinct from DR-41 (ATTACK_WAVE_INIT) which is server-computed |
WFBE_Server_PV_SupplyMissionCompleted (direct PV) + SupplyAmount truck var |
supplyMissionCompleted.sqf:2,9,26; supplyMissionStart.sqf:34
|
Critical | client broadcasts SupplyAmount on the truck and fires the completion PV directly → unlimited instant supply, bypassing the proximity loop; truck path, distinct from DR-53 (heli) |
RequestMHQRepair |
Server/PVFunctions/RequestMHQRepair.sqf:1, Server_MHQRepair.sqf:3
|
High | rebuild any side's HQ (cross-side); no alive/side/count/in-progress guard |
RequestNewCommander (direct-assign path) |
Server/PVFunctions/RequestNewCommander.sqf:8-13 |
High | force-assign commander to any team outside a vote window (no commander/admin/side check); distinct from DR-15/DR-47 vote paths |
RequestTeamUpdate |
Server/PVFunctions/RequestTeamUpdate.sqf:1-26 |
High | reprogram behaviour/combat/formation/speed for all teams of any side (enemy AI sabotage) |
RequestSpecial "RespawnST" |
Server_HandleSpecial.sqf:55-60 |
High | kill all supply trucks of any side |
RequestSpecial "repair-camp" |
Server_HandleSpecial.sqf:225-247 |
High | flip any camp to any sideID + global CampCaptured (territory forgery) |
RequestSpecial "upgrade-sync" |
Server_HandleSpecial.sqf:67-73 + Server_ProcessUpgrade.sqf:29
|
High | instantly complete any in-progress upgrade for any side (timer bypass) |
RequestSpecial "connected-hc" |
Server_HandleSpecial.sqf:195-209 |
High | inject own group into WFBE_HEADLESSCLIENTS_ID (HC-pool poisoning; only guard is owner != 0) |
RequestSpecial "update-clientfps" |
Server_HandleSpecial.sqf:75-84 |
High | zero another player's WFBE_AI_DELEGATION_<uid> FPS slot via foreign UID (targeted delegation-DoS) |
RequestSpecial "update-town-delegation" |
Server_HandleSpecial.sqf:86-95 |
High | append arbitrary vehicles to any town's wfbe_active_vehicles (deletion/grief) |
RequestSpecial "update-teamleader" |
Server_HandleSpecial.sqf:6-12 |
Medium | poison wfbe_teamleader → Server_OnPlayerDisconnected.sqf:57,102 deletes a live enemy unit on disconnect |
Action_RepairMHQDepot (client direct setVariable) |
WASP/actions/Action_RepairMHQDepot.sqf:23-28 |
High | client broadcasts cashrepaired=true and {_x setVariable ["supplyValue"…]} draining all own-side towns; no server validation |
WFBE_Client_PV_SupplyMissionStarted |
supplyMissionStarted.sqf:8 |
Medium | stamp LastSupplyMissionRun cooldown on any town (supply-mission DoS) |
WFBE_C_PLAYER_OBJECT |
playerObjectsList.sqf:1-34 |
Medium | spoof [ownObject, victimUID] into WFBE_SE_PLAYERLIST (displaces victim's entry; reward-redirect blocked by live getPlayerUID recheck) |
MARKER_CREATION (direct PV) |
Common_CreateMarker.sqf:82-83 |
Low | inject fake same-side map markers; global createMarker name-collision can overwrite real event markers |
AFKthresholdExceededName |
initAFKkickHandler.sqf:9-12 |
Low | client log-injection (no enforcement sink) |
Fix (one architectural change): make the PVF dispatcher capture the sender (the addPublicVariableEventHandler callback's _this select 1 is the value; the owner is available via the channel — or re-architect SendToServer to embed getPlayerUID player/owner player and have the server cross-check it against _this origin). Then each handler must re-derive side/commander/funds server-side from the authenticated sender, not from payload fields. This is the same server-authority redesign already named for the economy class (DR-1/6/14/16/22/23/27/28/41/44/49/50/52/53) — DR-55 establishes that the redesign must cover the entire handler list above, not a subset. Read/cosmetic channels confirmed clean (server-originated, no client mutation): PLAYER_RADIATED, REQUEST_SUPPLY_VALUE/SUPPLY_VALUE_REQUESTED, WFBE_DAYNIGHT_DATE, SERVER_FPS_GUI, HQ-alive/marker-infos, stagnation/compensation displays, wfbe_supply_<side> (server→all). Fix shapes per-handler in agent-hardening-backlog.jsonl #pvf-handler-sender-authentication.
DR-56 — ARTY_HandleSADARM.sqf: infinite while {true} thread leak per air-kill + per-frame setVelocity busy-wait — High (perf / scheduler exhaustion)
Common/Module/Arty/ARTY_HandleSADARM.sqf (spawned once per SADARM round via Common_HandleArtillery.sqf:33): :137-141 is if !(isNull _impactAreaSimulation) then { while {true} do { sleep 1; deleteVehicle _impactAreaSimulation } } — the object is deleted on iteration 1 but the loop has no exit, leaking one permanently-sleeping scheduled thread per SADARM air-kill for the rest of the mission. Separately, :38-44 is a waitUntil with no sleep that calls getPos/velocity/setVelocity every frame for the 10-20s parachute descent (the sibling loop at :50-72 correctly uses sleep 0.2, confirming the omission). Fix: replace :137-141 with a single deleteVehicle; add sleep 0.1 inside the :38 waitUntil. Fix shape in agent-hardening-backlog.jsonl#arty-sadarm-thread-leak.
DR-57 — Town patrols can never spawn: wfbe_patrol_active_last is reset to time every town-AI cycle — High (gameplay; an entire AI feature is dead at runtime)
Server/FSM/server_town_ai.sqf:67-68 unconditionally sets wfbe_patrol_active = false and wfbe_patrol_active_last = time on every pass of the per-town loop (~5s). The spawn gate at :295-296 then requires time - (_town getVariable "wfbe_patrol_active_last") > WFBE_C_PATROLS_DELAY_SPAWN (360s), but the timestamp was just refreshed milliseconds earlier in the same iteration, so the delta is always ~0 and never reaches 360. Town patrol groups never spawn for the entire match. (Distinct from the known AI1 ||-vs-&& loop bug in server_patrols.sqf:26, which is also confirmed still-unpatched on current master — see below.) Fix: remove the unconditional :68 timestamp reset; stamp wfbe_patrol_active_last only on the active→inactive transition (the completion path server_patrols.sqf:71-72 already does). Fix shape in agent-hardening-backlog.jsonl#town-patrols-never-spawn.
-
PLAYER_RADIATEDbroadcast (Client/Module/Nuke/radzone.sqf:102-104): serverpublicVariables the full player object to all clients per radiated player per 5s tick; should be(owner _x) publicVariableClient. Perf, Medium. -
playerObjectsListPVEH registered twice (Server/Init/Init_Server.sqf:73and:95bothCall Compilethe installer): every client connect races two spawns onWFBE_SE_PLAYERLIST→ duplicate entries. Remove:95. (Compounds known SG6.) -
skillDiffCompensation.sqf:31,89innerwhileloops have noWFBE_GameOverexit → continue running (incl.ChangeSideSupply/DB calls) for minutes after game-over. Add&& !WFBE_GameOver. -
monitorServerFPS.sqfbroadcastsWFBE_VAR_SERVER_FPSevery 8s but nothing reads it (the HUD usesSERVER_FPS_GUIfromserverFpsGUI.sqf) — dead orphan broadcast, removeInit_Server.sqf:599. -
Action_RepairMHQDepot.sqf:28writes the lowercase key"supplyvalue"(engine is case-sensitive; all readers use"supplyValue") → the intended all-town SV reset is a silent no-op. Correct the case or delete the debug residue. -
Client_BuildUnit.sqf:332,334duplicateFired→HandleReloadEH (current-master confirmation of audit V2, still unpatched here; PR #8 fixed it on the release branch only). -
AI_SquadRespawn.sqf:1Private ["_rcm'"]apostrophe typo (no-op while spawned; refactor hazard).
- Several audit-queue items confirmed still unpatched on current
master(they were PR #8 / release-branch fixes, not merged to master): SG5 (server_town_camp.sqf:135camp flag uses old_side), AI1 (server_patrols.sqf:26||zombie loop), AI2 (town mortar chain dead —WFBE_SE_FNC_ManageTownMortarsnever compiled +Server_SpawnTownMortars.sqf:20undefined_positions), SG4 (RequestOnUnitKilled.sqf:92undefined_objectTypeon kill-assist bounty), SG9 (Common_ChangeSideSupply.sqf:12_reasonguardcount>3should be>2, log-only, sole 3-arg caller isAttackWave.sqf:40). -
AntiStack DB
call compileon rawcallExtensionoutput (callDatabaseRetrieve.sqf:30etc., all 6 DB scripts) is a real server-side RCE-if-DLL-compromised surface — folded as a sharper citation under DR-7..DR-10 (useparseSimpleArray, notcall compile), not a new DR. -
SEND_MESSAGEreceiverClient_onEventHandler_SEND_MESSAGE.sqf:27 call compile— sharper citation under DR-46 (the receiver side of the same channel; confirms the broadcast executes on every client, not just the sender). - JIP/HC:
LocalizeMessage.sqf:30TeamstackwaitUntiland theInit_Client.sqf:406/:409/:502/:802main-threadwaitUntilchain have no timeouts → permanent client freeze if the relevant server broadcast is dropped or the server aborts mid-init. Owner hardening (bounded waits), extends DR-37's note.
Outcome: the deeper pass established the systemic result (DR-55: the whole PVF/PVEH/direct-PV surface is client-forgeable, ~18 newly-enumerated handlers) plus DR-56 (ARTY perf) and DR-57 (town patrols dead). Minor perf/dead/logic findings routed; six known audit items confirmed still-unpatched on master; DR-7..10 and DR-46 given sharper citations. No gameplay source changed.
Previous: Testing workflow | Next: Implementation plan
Main map: Home | Fast path: Quickstart | Agent file: agent-context.json
Home | Agent Guide | Current live state | Release 1.2.2 (B91) | Quickstart | Progress | Lifecycle wait-chain | Join/disconnect | Parameters/build | Assets/config | SQF atlas | PV index | Modules | Support/specials | Commander/HQ | Commander vote/reassign | Construction/CoIn | Construction cleanup | WDDM compositions | Factory/purchase | Upgrades/research | Towns/camps/capture | Victory/endgame | Markers/cleanup | Server runtime | AI runtime/HC | AI commander audit | HC delegation | Town AI safety | Commander reassignment | Resistance supply | Player UI workflow | UI atlas | Respawn/death | Gear template filter | Vehicle cargo loop | Service guards | UI IDD repair | UI design inspiration | WASP overlay | Feature status | Source propagation | release readiness | Tooling readiness | Integration trust | AntiStack DB | Owner decisions | Shelved registry | Abandoned feature revival | Hardening roadmap | PVF dispatch | Server authority | ICBM authority | Attack-wave authority | Telemetry families | AICOM V2 cutover | Consumer port map | Testing workflow | Server ops | Web tools | Ecosystem repos | Arma 2 OA refs | A2 traps | OA compatibility audit | Coverage ledger | Navigation inventory | Pruning ledger | Knowledge roadmap | Agent context | Collab protocol | Worklog | Audit archive 2026-07 | Briefing reference | Utes invasion concept
- Shelved AICOM concepts - revivable someday ideas (owner-shelved 2026-07-03)
Docs rule: source-backed claims only; Arma 2 OA scripting docs only; gameplay edits start in Missions/[55-2hc]warfarev2_073v48co.chernarus.
- Getting started
- Status and coordination
- Agent context
- Agent collaboration protocol
- Agent worklog
- Agent worklog archive
- Progress dashboard
- PR cleanup and integration lab
- Shelved PR #169: gear price double-count
- Shelved PR #194: Chernarus no-trees
- Coordination board
- Codebase coverage ledger
- Bottleneck removal queue
- Current source status
- Wiki mirror reconciliation
- Navigation inventory
- Registers
- Agent orchestration
- Architecture
- Architecture overview
- Mission entrypoints and lifecycle
- Lifecycle wait chain
- Player join/disconnect and AntiStack lifecycle
- Mission parameters/localization/build inputs
- Stringtable localization key-family catalog
- Source inventory
- Content structure and maps
- Assets/config/localization/parameters
- Mission start parameters index
- Code and networking
- Gameplay systems
- Core systems index
- Gameplay systems atlas
- Commander/HQ lifecycle atlas
- Economy, towns and supply
- Economy system reference
- Balance asymmetries
- Anti-stack skill-balance mechanic
- Empty-side supply income stagnation
- Towns, camps and capture atlas
- Victory and endgame atlas
- Victory conditions reference
- Territorial victory reference
- Marker cleanup and restoration
- Marker loop engine and registries
- Map marker families content catalog
- Marker subsystem function reference
- Client marker FSM updater map
- Support specials and tactical modules
- SCUD TEL tactical munitions
- Naval HVT objectives (carriers/SCUD)
- SCUD saturation strike mechanic
- Takistan airfield FPV drone design
- Construction and CoIn systems
- Structure damage reduction & friendly-fire
- Construction logic list cleanup
- Flak tower & WDDM anchor compositions
- Resistance supply scaffold
- GUER Insurgents faction overview
- GUER Insurgents branch audit
- GUER insurgent player economy
- GUER Commissar Panel
- GUER air-defense loop (Ka-137/Mi-24)
- Upgrades and research atlas
- Supply mission architecture
- Supply mission authority cleanup
- Current supply helicopters PR1
- Respawn and death-loop lifecycle
- Vehicle theft economy pitch
- GUER tunnel network pitch
- Content, reference and catalogs
- Faction unit/vehicle roster catalog
- Auxiliary/SF/civilian unit catalog
- Gear store loadout route catalog
- Upgrade research (cross-faction)
- Gear store price and upgrade catalog
- Gear store catalog (complete, per faction)
- Defense structures catalog
- Artillery reference per faction
- AI squad team templates catalog
- Town AI lifecycle reference
- Town AI group composition catalog
- Class-skill system reference
- Player skill abilities reference
- Default gear template content catalog
- Chernarus map content reference
- Takistan map content reference
- Takistan features
- Takistan parity reference
- Takistan oilfields objective reference
- IRS IR-smoke countermeasure
- Arty module special munitions
- Zeta cargo sling-load reference
- Spawn primitive function reference
- Kill and score pipeline
- Waypoint helper function reference
- Position and proximity function reference
- Side/team state function reference
- Player AI watchdog and recovery
- AICOM stuck-recovery v2
- LoadoutManager data-model contributor guide
- Discord status bot setup and reference
- GLOBALGAMESTATS extension reference
- New player quickstart (player guide)
- Optional client mods (player guide)
- Earning funds and score (player guide)
- Vehicle service and logistics (player guide)
- Commander's handbook (player guide)
- Tactical support menu
- Paradrop player experience
- Supply missions (player guide)
- In-game briefing & Diary field manual
- Playable maps catalog
- Faction root variables reference
- Faction base structures catalog
- Counter-battery radar system
- Bank, Reserve and Artillery Radar structures
- Map ruleset model and object config
- Countermeasures module reference
- Vehicle countermeasure (flares/spoofing)
- UAV terminal and spotter system
- Artillery firing function reference
- Service Point pricing model
- Medic redeployment truck (forward spawn)
- Side-patrol runtime and convoy mechanics
- Day/night cycle and weather system
- Config lookup helper reference
- CIPHER sort utilities reference
- Modded maps status and content
- BattlEye filter setup and OA taxonomy
- Player squad/group join protocol
- AutoFlip vehicle recovery
- Engine stealth fuel toggle
- Valhalla vehicle climbing-assist
- Missile and ordnance Fired-EH reference
- Vehicle equip and rearm reference
- Array and collection utilities
- Server composition spawner reference
- Upgrade queue server loop
- Map boundaries and off-map enforcement
- Namespace/profile/diagnostic utilities
- Group bool getVariable A2-OA trap
- Vehicle weapon balance init
- View distance auto-throttle
- Camp & respawn-camp getters
- Performance audit writer
- Site clearance (bulldozer)
- Factory queue cancel & refund
- AI commander tunable constants
- Experimental feature-flag constants
- Flag system quick reference
- Mission tunable constants catalog
- Gear parsing & cargo capacity
- Structure dressing function
- Paradrop delivery functions
- ICBM nuke client VFX & radiation
- Server HandleSpecial router
- LocalizeMessage chat router
- Gear buy-menu render & price functions
- Server broadcast & telemetry loops
- Per-unit client init pipeline
- Vehicle marking & texture pipeline
- Defense category & budget
- Legacy AI order primitives
- Commander-team driver
- AICOM command verbs
- AICOM behavior fix taxonomy
- AI commander wildcard deck reference
- AICOM aircraft and airfield system
- Static-defense manning
- End-of-game stats screen
- AI commander execution loop
- Deployable bipod / weapon resting
- Town-economy getters
- Server-init deadspawn & airfield probe
- GUER VBIED detonate action
- Resource income-tick engine
- AI commander treasury accessors
- PVF send-helper contracts
- AICOM logging & AICOMSTAT telemetry
- AICOMSTAT v2 event census
- WASPSCALE v2 telemetry
- WASPSCALE v2-ext coverage audit
- Telemetry families reference
- Group lifecycle & entity reaping
- Batch AI spawner orchestrator
- Client funds/income HUD readout
- Server group GC & cap warning
- Town runtime tuning constants
- Client input/hotkey handler
- WASP base-repair system
- WASP DropRPG launcher/ordnance
- CoIn construction-interface client engine
- Town-capture garrison & airfield rebuild
- Map-control & minimap templates
- Client FPS & state telemetry
- Client service-proximity getters
- Airfield-exclusive roster & unit hints
- Unit-camera spectator system
- Town-garrison patrol/defense worker
- RequestTeamUpdate squad-discipline
- Arma2Warfare GPT assistant
- LoadoutManager build configs & defines
- GLOBALGAMESTATS extension logging
- Discord bot instrumented logging
- Eden/Everon & Taviana map content
- Cruise missile strike asset
- AI / HC
- AI headless and performance
- AI mods and pathfinding reference
- Headless client scaling and topology
- AI runtime/HC loop map
- Headless client init and stat loop
- HC delegation target selection
- Player AI caps and role balance
- Old WarfareBE FPS comparison
- AI commander autonomy audit
- Upstream BE 2073 AICOM delta
- Parent 2.073 divergence audit
- AI commander capture & fun plan
- AI commander B69 improvement roadmap
- AI commander B69 implementation sketches
- AICOM V2 cutover status
- Headless delegation and failover
- Commander reassignment call shape
- GUER Director living-resistance pitch
- Quality and operations
- Foundation perf findings & Tier-3 dead-ends
- Dead/stale code register
- Commander vote/reassignment
- Attack-wave authority
- Server runtime and operations
- Server ops runbook
- JIP enrollment & client data delivery (b74.2 lessons)
- Server gameplay runtime atlas
- PerformanceAuditAnalyzer
- Performance opportunity sweep
- Documentation plan
- Knowledge platform roadmap
- Wiki quality audit
- Wiki pruning and relevance ledger
- Audit findings queue (2026-06-03)
- Deep review findings
- Client UI / server-loop perf findings
- Performance gain simulation
- Self-host testing field notes
- Cleanup and work lanes
- Hardening and authority
- UI / player workflows
- Client UI, HUD and menus
- UI HUD and dialogs
- Player UI workflow map
- Client UI systems atlas
- UI IDD collision repair
- UI control class library reference
- UI theme palette and style macros
- UI design inspiration 2026-07
- Available-actions client gate FSM
- Gear/loadout/EASA atlas
- Gear template profile filter
- Vehicle cargo equip loop bounds
- Factory and purchase systems atlas
- Service menu affordability guards
- WASP overlay
- Class-skill system reference
- Skin selector and class swap
- Earplugs audio toggle
- Mission audio catalog
- HQ radio knowledge-base catalog
- QoL trio player hints
- Player vehicle/travel actions
- Tooling / release / integrations
- Tools and build workflow
- Warfare web tools
- Ecosystem & companion repos
- Zargabad tooling parity
- July 2026 release readiness
- Operator monitor and CPU affinity tools
- Tooling release readiness audit
- Source fix propagation queue
- Agent release readiness ledger
- Release source intake map
- Testing/debugging/release workflow
- Current RPT release gate
- RPT telemetry consumer port map
- External integrations
- Integration trust boundary audit
- AntiStack database extension audit
- Community & Dev
- Community & Dev
- Miksuu upstream wiki import / archive index
- Upstream changelog feature leads
- Developer history and upstream lessons
- Upstream Miksuu commit intel
- Upstream mining ledger
- Archive script mining v2
- Upstream BE 2073 AICOM delta
- Parent 2.073 divergence audit
- PR8 and Drone upstream lesson match
- Development lessons learned
- External research reports
- Audit archive 2026-07
- Briefing reference
- Utes invasion concept
- Miksuu archive: Home
- Miksuu archive: Welcome
- Miksuu archive: Big announcements
- Miksuu archive: Changelog
- Miksuu archive: Development process
- Miksuu archive: Discord bot
- Miksuu archive: Gameplay videos
- Miksuu archive: LoadoutManager
- Miksuu archive: Chernarus script architecture
- Base-game visual catalogs
- Compatibility and references
- HC upstream history and lessons
- Player stats branch audit
- BuyMenu EASA QoL branch audit
- Perf quick wins branch audit
- Commander positions branch audit
- Zargabad branch audit
- Quad AI Commander concept
- Arma 2 OA external reference guide
- Base-game config & image reference
- Arma 2 OA compatibility audit
- Arma 2 OA agent traps reference
- Arma 2 OA command versions
- Wiki source consistency
- External Arma 2 OA reference index