1
# ConfigLib 1.11.0 static forensic analysis
**Artifact:** `G:\GameDev\Hostile\configlib_1.11.0.zip`
**Analysis date:** 2026-09-01
**Primary ZIP SHA-256:** `9E15E68AA11723405BE02054FACFEEB08DD4499773D555E3889FDA62A9A89C50`
**Method:** static-only analysis; the target DLL was never loaded or executed
## Executive conclusion
**Confirmed: this exact archive contains deliberately concealed, out-of-purpose malicious code.** The code is a conditional availability-sabotage payload embedded in `configlib.dll`. It automatically activates through a CLR module initializer, waits for ConfigLib's normal configuration-loading lifecycle event, and then operates only on multiplayer clients. It scans every loaded .NET assembly for cheat-related type-name fingerprints and broad obfuscation characteristics. If a condition matches, it waits a randomized period and corrupts internal Vintage Story client state.
This is not ambiguous telemetry, anti-cheat reporting, license enforcement, or a defensive block. It does not warn the user, refuse to load, report a detected mod, or stop at disconnecting from a server. Every fired callback necessarily nulls the game's loaded-entity collection or empties its packet-handler array, and it usually corrupts several additional UI/runtime fields. Other randomized actions explicitly set `KillNextFrame`, force menu/disconnect flags, mark the client disposed, call leave/restart-like methods, or reduce the frame limiter to a near-zero value.
The intent to conceal is supported by independent evidence:
- the payload is placed under the misleading name `YamlDotNet.Serialization.SettingsBuilder`, although it is absent from genuine YamlDotNet;
- its source file is named `AdditionalStuff.cs`, while the public repository specifically ignores `*AdditionalStuff*`;
- the same public commit that added that ignore rule also added the otherwise unexplained lifecycle event used only by the hidden file;
- trigger names are hidden as CRC32 constants;
- callback timing and effects are randomized;
- detection exceptions are silently swallowed;
- the method that performs sabotage is misleadingly named `ReloadFromConfigs`;
- the portable PDB embeds the complete hidden source and maps it directly to the malicious IL.
The target is **the byte-for-byte official 1.11.0 release asset**, not a third-party repack. Publication/build custody is strongly tied to the official release workflow. The DLL is not Authenticode-signed, however, and the hidden source has no individual author signature or Git commit. This report therefore does not claim which credited human wrote or approved it.
The confirmed malicious payload is confined to in-memory game-client sabotage. I found **no evidence in this sample** of OS persistence, credential theft, external command-and-control, HTTP/socket exfiltration, process or shell execution, registry changes, native injection, file encryption, save-file deletion, or a downloaded second stage. On the evidence available, an operating-system reinstall is not indicated solely because this DLL was present. The archive remains untrustworthy and should not be loaded.
## Risk summary
| Finding | Severity | Classification | Confidence |
|---|---|---|---|
| Concealed multiplayer client sabotage | **Critical** | Deliberate, unrelated to ConfigLib's stated purpose | Confirmed from C#, raw IL, and embedded original source |
| Generic obfuscation detector can target unrelated mods | **High** | Part of malicious payload; broad false-positive design | Confirmed logic; independent artifacts strongly corroborate false positives |
| Client-controlled arbitrary server event injection | **High** | Purpose-adjacent network design vulnerability | Confirmed data/control path; ultimate server effect depends on runtime handlers |
| Server-controlled configuration path escape on clients | **High** | Purpose-adjacent path-validation vulnerability | Confirmed path construction and read/write paths |
| Weak bounds/validation in registry and setting packets | **Medium** | Robustness and denial-of-service exposure | Confirmed input paths; transport limits may reduce practical impact |
| Recursive expression parsing without a depth limit | **Medium** | Malformed-definition denial-of-service exposure | Confirmed parser structure; practical threshold not detonated |
| Harmony patch and file-watcher cleanup defects | **Medium/Low** | Ordinary implementation defects | Confirmed in public and compiled code |
| Definition-supplied links opened after user click | **Low/contextual** | Intended UI feature with trust implications | Confirmed; not automatic, game API may validate |
## Immediate response
1. Do not load this archive or its DLL. Close Vintage Story before removing it; restarting is necessary to unload a module initializer and any already-mutated in-process state.
2. Quarantine or remove every copy of affected ConfigLib releases from client and server mod paths and caches. The confirmed affected range begins with 1.10.9 and extends through 1.12.0; 1.10.11 could not be recovered but is bracketed by malicious releases.
3. Prefer a clean rebuild from reviewed source or an independently audited replacement. Do not rely on a surgical binary patch of this release.
4. Preserve this exact sample and hashes if evidence may be needed. The submitted archive has not been modified, deleted, or executed during this review.
5. If it was previously loaded in multiplayer, preserve logs, back up worlds, and inspect for interrupted saves. The payload can crash/disconnect the game and cause loss of unsaved state, but direct save corruption is not present in its code.
6. If it was used only in single-player, the hardcoded malicious callback returns before scanning. That lowers exposure to this exact payload but does not make the binary trustworthy or address the other vulnerabilities below.
## 1. Evidence handling and artifact identity
### Archive provenance
The local file's Windows download metadata points to the [official ConfigLib mod page](https://mods.vintagestory.at/show/mod/9551) and Vintage Story Mod DB CDN. A fresh copy obtained from the [official 1.11.0 download endpoint](https://mods.vintagestory.at/download/76348/configlib_1.11.0.zip) was 210,445 bytes and had the same SHA-256. A byte comparison was identical.
This establishes that the payload was present in the publisher-hosted artifact; it was not inserted into the submitted copy after publication.
### Complete archive inventory
The ZIP has exactly five ordinary deflated entries. CRC validation passed. It has no archive comment, duplicate names, encrypted entries, traversal paths, nested archive, or unexpected extra field.
| Entry | Size | SHA-256 | Assessment |
|---|---:|---|---|
| `configlib.dll` | 401,408 | `42EDF8D55423260038D6F1B61FC33515011D8EE9802AFB1B2E9F717C9FC710FC` | Contains the malicious payload |
| `configlib.pdb` | 54,928 | `9FAF53383ADBA9A8C1FBAEB9449DEAD1577E366AF001BDAFB808EE53EAE1A818` | Portable PDB; embeds the hidden payload source |
| `configlib.deps.json` | 3,653 | `613D93623DA251243A0F457150A5C34A81D225EC77325585B8C74C8A3ABFFE15` | Expected .NET dependency metadata |
| `modicon.png` | 21,869 | `8EA249397EB69309117E1966A0C9BB1B74C81DD38E0FB1B52006EDB98E6BFB09` | Valid PNG; no trailing payload or anomalous chunks |
| `modinfo.json` | 435 | `AFAEF2CB687E9CD98970A872474367F63C373D52621E6DBBDE0A0DC1805F1E55` | Expected mod manifest |
The manifest declares ConfigLib 1.11.0, a universal GUI configuration mod that is client-required and server-optional. The DLL's assembly/file version remains 1.10.0.0 and its informational version is `1.10.0+0d1113d2124bf5edfb940d0ef81f1674b7064fd3`. The project separately sets its mod version, so this version mismatch is not itself evidence of tampering.
### Binary structure
`configlib.dll` is a normal managed PE32/I386, IL-only DLL rather than a native packer/dropper:
- CLR MVID: `de84b3c3-6ff7-4423-a5f0-bf72b0cf2707`
- 507 types, 2,905 methods, and 1,200 fields
- ordinary `.text`, `.rsrc`, and `.reloc` sections
- no overlay, exports, TLS callbacks, P/Invoke methods, or suspicious native imports
- only the normal CLR bootstrap import `mscoree.dll!_CorDllMain`
- no Authenticode signature and no CLR strong name
- one CLR resource, `ILRepack.List`, which lists the expected merged assemblies: ConfigLib, SimpleExpressionEngine, and YamlDotNet
- no embedded executable, script, encrypted blob, or second-stage resource
The DLL is not broadly obfuscated. Normal symbols and a portable PDB are present. The malicious code instead relies on semantic camouflage and delayed, nondeterministic effects.
## 2. Exact malicious execution chain
The chain is automatic and requires no call from another mod:
1. When the CLR loads the assembly, `<Module>..cctor` calls `YamlDotNet.Serialization.SettingsBuilder.Init()`.
2. `Init`, marked `[ModuleInitializer]`, silently subscribes the hidden handler to the static `ConfigLibModSystem.ConfigsChanged` event.
3. ConfigLib's normal `AssetsLoaded` lifecycle loads/applies configuration and invokes `ConfigsChanged`.
4. The hidden handler rejects server and single-player contexts, scans every loaded assembly on a multiplayer client, and registers one or two delayed callbacks when its tests match.
5. The callbacks call `ReloadFromConfigs()`. Despite its name, that method does not reload configuration: it casts the world to internal `Vintagestory.Client.NoObf.ClientMain` and corrupts game state.
Primary local evidence:
- [raw module initializer IL](G:/GameDev/Hostile/.codex-forensics/configlib_1.11.0_9e15e68a/il/configlib.il:2)
- [hidden SettingsBuilder source](G:/GameDev/Hostile/.codex-forensics/configlib_1.11.0_9e15e68a/decompiled/YamlDotNet/Serialization/SettingsBuilder.cs:17)
- [AssetsLoaded lifecycle invocation](G:/GameDev/Hostile/.codex-forensics/configlib_1.11.0_9e15e68a/decompiled/ConfigLib/ConfigLibModSystem.cs:194)
- [raw IL for the hidden methods](G:/GameDev/Hostile/.codex-forensics/configlib_1.11.0_9e15e68a/il/configlib.il:30848)
The module initializer is the sole module initializer in the assembly. Every reference to the internal `Vintagestory.Client.NoObf` namespace and both `RegisterCallback` calls in the entire DLL belong to this payload.
## 3. Trigger logic
### Environment gate
The handler proceeds only when:
- `api` is an `ICoreClientAPI`; and
- `clientApi.IsSinglePlayer` is false.
The hardcoded sabotage therefore targets multiplayer clients, not a dedicated server or single-player session. Once inside that gate it enumerates `AppDomain.CurrentDomain.GetAssemblies()` and calls `Assembly.GetTypes()`.
### Family A: control characters in type names
For each loaded assembly, the code tests whether any type name contains a Unicode character below U+0020. This is a generic marker for one style of identifier obfuscation.
On any match it schedules sabotage after:
```text
NatFloat(5, 4, UNIFORM) * 107471 milliseconds
```
Vintage Story's uniform `NatFloat(5,4)` returns approximately `[1,9)`, so the delay is about 107,471–967,239 ms: **1m47s to under 16m07s**, with an expected value near 8m57s. This range is derived from the official [Vintage Story `NatFloat` implementation](https://github.com/anegostudios/vsapi/blob/master/Math/NatFloat.cs#L1637-L1641).
### Family B1: concealed cheat-feature fingerprints
The next detector checks eight type-name prefixes independently within each assembly. It calculates CRC32 rather than storing readable names and requires at least three matches in the same assembly.
Using Vintage Story's official UTF-8 [GameMath.Crc32](https://github.com/anegostudios/vsapi/blob/master/Math/GameMath.cs#L1135-L1143), all constants recover exactly:
| Prefix | Hashed length | Decimal CRC32 | Important predicate detail |
|---|---:|---:|---|
| `Aimbot` | 6 | `3606486923` | Prefix match |
| `InstantShot` | 11 | `3515110866` | Prefix match |
| `KillAura` | 8 | `2049016528` | Prefix match |
| `MapCursorTeleport` | 17 | `2562349273` | Prefix match |
| `Nuker` | 5 | `2667834024` | Prefix match |
| `VintageClient` | 13 | `3614613420` | Prefix match |
| `BlockFinder` | 11 | `99783805` | Code requires a longer type name, so this must be a prefix plus at least one character |
| `Esp` | 3 | `3708276016` | Code requires a longer type name, so this must be a prefix plus at least one character |
The coherent names make cheat-client fingerprinting the clear inference. CRC32 is collision-prone, so the exact binary predicate is technically “prefix with matching CRC,” not cryptographic proof of a uniquely named target.
### Family B2: generic short-name heuristic
Independently, the code collects every type name and every reflected member name from an assembly. It counts names that:
- are one or two characters long; and
- consist only of ASCII letters or digits.
If these exceed **22%** of all collected names, that assembly triggers. This is a crude general obfuscation/minification heuristic, not a targeted signature. It can match unrelated closed-source or obfuscated mods.
Family B1 and B2 are ORed. Either schedules sabotage after:
```text
NatFloat(5, 4, UNIFORM) * 92439 milliseconds
```
That is approximately 92,439–831,951 ms: **1m32s to under 13m52s**, with an expected value near 7m42s.
Family A and Family B are independent. If both match, two destructive callbacks can be registered. The scanner catches and discards exceptions without logging them.
## 4. Sabotage effects and probabilities
The callback samples one uniform value `v` in approximately `[0,2)`. It first selects one mutually exclusive primary action:
| `v` interval | Direct action | Approx. probability |
|---|---|---:|
| `[0, 0.173234)` | `ClientMain.disposed = true` | 8.6617% |
| `[0.173234, 0.32323)` | `DeltaTimeLimiter = 2 * float.Epsilon` (decompiled as `3E-45f`) | 7.4998% |
| `[0.32323, 0.53435)` | `KillNextFrame = true` | 10.5560% |
| `[0.53435, 0.7343)` | `exitToMainMenu = true` | 9.9975% |
| `[0.7343, 1.1892)` | `exitToDisconnectScreen = true` | 22.7450% |
| `[1.1892, 1.3232)` | calls `ClientMain.Start()` | 6.7000% |
| `[1.3232, 1.633)` | calls `ClientMain.SendLeave(0)` | 15.4900% |
| `[1.633, 2)` | no primary-chain action | 18.3500% |
It then applies cumulative corruption based on the same value:
- if `v < 1.7433`, set `GuiComposers = null` — 87.165%;
- if `v < 1.8433`, set `ScreenRunningGame = null` — 92.165%;
- if `v < 1.9433`, set `LoadedEntities = null` — 97.165%;
- otherwise, replace `PacketHandlers` with an empty array — 2.835%.
These are separate conditions, so low values null all three GUI/screen/entity fields. Most callbacks therefore damage several subsystems at once.
**Invariant:** because `v` is always below 2, every callback either nulls `LoadedEntities` or empties `PacketHandlers`. A callback never completes harmlessly. Exact downstream stack traces vary by Vintage Story version and timing, but forced disconnects, broken rendering/UI/network processing, null-reference faults, or termination are the foreseeable and intended availability effects of these explicit internal writes.
The effect is visible in [the decompiled callback](G:/GameDev/Hostile/.codex-forensics/configlib_1.11.0_9e15e68a/decompiled/YamlDotNet/Serialization/SettingsBuilder.cs:63) and independently in [raw IL](G:/GameDev/Hostile/.codex-forensics/configlib_1.11.0_9e15e68a/il/configlib.il:30980).
## 5. Why this is deliberate concealment, not accidental code
### Embedded source and SourceLink
The portable PDB ID is `D1CDC528A4C49FFFA5FE7A330794BEC5CE215845`. It records an original build document:
```text
D:\Projects\VintageStory\configlib\configlib\source\AdditionalStuff.cs
```
The PDB contains the complete 5,830-byte source for that document. Its SHA-256 is:
```text
0156AE0438B2A93F9090CBF7ACDA076F2703E012DBF9893E081809B5B9C2F437
```
The embedded source defines the malicious `YamlDotNet.Serialization.SettingsBuilder` class. PDB sequence points map the module initializer, assembly scans, CRC tests, obfuscation heuristic, and state-corruption callback to that file. This removes decompiler interpretation as a plausible explanation.
SourceLink maps the build tree to the public repository at commit `0d1113d2124bf5edfb940d0ef81f1674b7064fd3`, but the resulting [AdditionalStuff.cs SourceLink URL](https://raw.githubusercontent.com/maltiez2/vsmod_configlib/0d1113d2124bf5edfb940d0ef81f1674b7064fd3/configlib/source/AdditionalStuff.cs) returns 404. All ordinary project source documents recorded by the PDB match the public 1.11.0 release tree; `AdditionalStuff.cs` is the sole unpublished addition.
### Repository concealment scaffold
Public commit [710f40d99e394aabfdb1f60fc5575461afc5f2dd](https://github.com/maltiez2/vsmod_configlib/commit/710f40d99e394aabfdb1f60fc5575461afc5f2dd), dated 2025-11-11, makes three coordinated changes:
- adds `.gitignore` pattern `*AdditionalStuff*`;
- adds the obsolete static `ConfigLibModSystem.ConfigsChanged` event;
- invokes that event after configuration assets load.
The hidden compiled file is exactly `AdditionalStuff.cs`, and its module initializer subscribes to exactly that event. No ordinary public source consumer explains the hook.
The [public 1.11.0 commit](https://github.com/maltiez2/vsmod_configlib/commit/d207a6ed47ee859cd74e310f5e5569b359af2263) discloses only version/dependency changes and minor UI/debug edits. The official binary was uploaded 38–49 seconds before that commit, consistent with a local working-tree build/upload followed immediately by the public version commit.
### Genuine YamlDotNet comparison
The DLL merges YamlDotNet 13.7.1. Comparison with the genuine dependency found:
- target merged YamlDotNet namespace: 256 decompiled files;
- genuine YamlDotNet: 255 files;
- sole added type/file: `Serialization/SettingsBuilder.cs`;
- 253 common files decompiled byte-identically;
- the two remaining common files differ only cosmetically due to merging/decompilation, with equivalent IL.
Genuine YamlDotNet has no ConfigLib event reference, Vintage Story `ClientMain` access, module initializer, or corresponding `SettingsBuilder`. The malicious code is camouflaged inside the third-party namespace; it is not an upstream library behavior.
### Attribution boundary
Evidence strongly ties the official artifact to Maltiez/maltiez2's release/build workflow:
- the official Mod DB asset is byte-identical;
- assembly metadata and SourceLink identify the repository;
- the PDB contains the local ConfigLib build path;
- ordinary PDB sources match the public repository;
- official upload and the maltiez2 version commit are separated by seconds.
However, the DLL has no Authenticode signature, `AdditionalStuff.cs` has no commit/author metadata, and the package credits two authors. The evidence supports attribution to the official release process, not a conclusive claim that any particular individual wrote the hidden file. In particular, nothing here establishes that the other credited author authored it.
## 6. Release lineage
Official Mod DB/CDN artifacts were statically sampled across the release history. “Clean” below means the known `AdditionalStuff`/`SettingsBuilder` payload was absent; it is not a blanket trust endorsement.
| Release | Static result |
|---|---|
| 1.10.0–1.10.8 | Known hidden class absent |
| 1.10.9 | First confirmed release containing the hidden implementation |
| 1.10.9–1.10.10 | Hidden implementation present; these older variants also contain rare zero-interval callbacks that inject random input or attack the player. Those extra actions are **not** in 1.11.0 |
| 1.10.11 | Retracted artifact could not be recovered; bracketed by confirmed malicious 1.10.10 and 1.10.12 |
| 1.10.12 | Adds the first six CRC fingerprints |
| 1.10.13 | Expands the set to eight fingerprints |
| 1.10.14 | Adds the generic `>22%` short-name heuristic |
| 1.11.0 | Submitted payload: detectors plus randomized `ClientMain` state sabotage; older fake-input/self-attack callbacks removed |
| 1.11.1 | Hidden source identical to 1.11.0 |
| 1.12.0 | Hidden source identical to 1.11.0 |
| 1.13.0 | Known payload absent in compiled asset, but the release was retracted |
| 1.13.1 | First non-retracted release in which the known payload is absent |
Representative release hashes:
| Release | ZIP SHA-256 | DLL SHA-256 |
|---|---|---|
| 1.10.7, known payload absent | `86DF2166C82677CD559B629AB4A560249F7B58A7B8E5A972707F9EAF5FCD92E7` | `F41322C5E27F85F3C777F368DBA0AC64B719D60717A9A7C705C43C3F7A46EF6D` |
| 1.10.8, payload absent/retracted | `AD5432C4ECCE754B8C8237044A02F075DF8117BFCD01D690D6D1AB2F375847E7` | `94785616D546C5AC14774A1AAF4B7323CE8E2C5F8D4A13E215A6732F0F0481D7` |
| 1.10.9, first confirmed malicious | `55296C3E0E98E4B830DE81F0763E28EBDEC70BE873E1C31052B4A3623F5DF56B` | `3218A11A8D025F159F671BBD2E6E194929AA408DD47B2AF820DE8CC4BCD47B19` |
| 1.11.0, submitted target | `9E15E68AA11723405BE02054FACFEEB08DD4499773D555E3889FDA62A9A89C50` | `42EDF8D55423260038D6F1B61FC33515011D8EE9802AFB1B2E9F717C9FC710FC` |
| 1.12.0, malicious | `7376D892EE4B9DC8D435E4B4B32E964773E770D5F6EC01F2C913EF49B729D9FC` | `25D8BB4B3737236D48E6FC76F3494170C984693B7D40A67335DA46A106E28F67` |
| 1.13.0, payload absent/retracted | `57E6D42C3B7EF832162FDC7E6F4739A9556BA9A2EAAAB0DE6C64CF04F1AE15B0` | `AB8A47834AA7C02A819D557A0E093BCABA6B3E72C61A1E4DD97C6BF6A966AB6F` |
| 1.13.1, payload absent/active at review time | `4CB434E586A129391F9A5E999E5BBF5D0FAFBD4FFAE53A5F4403D40AF2FAF522` | `ED062B33E5CF17DAC6BC84D5787AF05CAB23E18246EF0C8CDE88EC1A9792C3E3` |
The [official release page](https://mods.vintagestory.at/show/mod/9551) contains cryptic 1.13.0/1.13.1 notes about removing and retaining “this piece of code.” The static lineage independently identifies what disappeared. A release lacking this known class should still receive a fresh, whole-binary audit before it is trusted.
## 7. Broad false-positive exposure
The generic 22% test does not establish cheating. To assess its breadth without loading third-party DLLs, two unrelated official mod artifacts implicated in public reports were parsed as metadata:
| Artifact | Types | Control-character hits | Named CRC hits | Declared-name short ratio |
|---|---:|---:|---:|---:|
| Caves and Caverns 0.5.1 | 171 | 0 | 0 | 51.06% (1,975 / 3,868) |
| VS Radio 1.2.0 | 29 | 0 | 0 | 88.62% |
Reference hashes:
- Caves and Caverns ZIP: `A80DD4C668A0426019F927E74D076C2E2F290400A59CB19E13C31427D0BB416F`; DLL: `787BC843A7D152F9A7223ECDED818E82458761BB8CACB5D5CF80277DB6490ABC`.
- VS Radio ZIP: `70124FCCE77900DBE1EC9A09B279F7F0A7B1DC479D823C7B740EB397419F0D72`; DLL: `0513B02CD3654CBE5AD0B3C0EA709B95BAE01CC0D6D450EFF6B0A5319DA8E82A`.
The payload's exact runtime computation uses reflection and includes inherited members, while this safe scanner measured declared metadata names. The exact percentage can therefore shift at runtime. Both static ratios are nevertheless far above 22%, and the result is consistent with multiplayer crash reports on the [Caves and Caverns page](https://mods.vintagestory.at/show/mod/9065) and [VS Radio page](https://mods.vintagestory.at/show/mod/61085). This is strong corroboration—not a dynamic proof—that the generic heuristic punished legitimate obfuscated mods.
## 8. Behavior tied to ConfigLib's stated purpose
The remainder of the first-party code is substantially consistent with a universal configuration GUI. Reviewed legitimate behavior includes:
- discovering `configlib-patches.json` definitions from content/code mods;
- reading and writing YAML/JSON configuration under the game data directory;
- file watchers for live reload of managed configuration;
- validation, formatting, mappings, expressions, and search;
- a unified VSImGui configuration window and optional definition-supplied links;
- applying configuration-derived asset/settings patches;
- a public API for custom managed configurations;
- synchronizing server-side definitions/settings through Vintage Story's internal registry/network channel;
- checking `Privilege.controlserver` before ordinary server-setting changes;
- publishing setting/config save/change events;
- Harmony-patching the pause menu to add a Mods settings button;
- bundling YamlDotNet and SimpleExpressionEngine as implementation dependencies.
These capabilities can legitimately be powerful because a config framework mediates files, assets, GUI, and multiplayer settings. They are not evidence of malware by themselves. The hidden `SettingsBuilder` type, its initializer, assembly detectors, callbacks, and `ClientMain` writes are categorically outside that purpose.
## 9. Other security-relevant findings
These issues are separate from the deliberately hidden payload. They are mostly unsafe implementations of intended features rather than proof of additional malicious intent.
### 9.1 High: arbitrary client-to-server event injection
The server registers a network handler for `ConfigEventPacket`. Its `SendEvent` handler accepts a client-supplied event name and serialized data, deserializes the data, and calls the server event bus directly:
```text
api.Event.PushEvent(eventPacket.EventName, ...)
```
There is no privilege check, event-name allowlist, namespace validation, or local exception boundary. A custom client can therefore emit arbitrary named server events over `configlib:events`, potentially reaching ConfigLib or other mods' listeners.
A concrete in-assembly failure path is:
```text
client packet with event name configlib:config-reload
-> SendEvent
-> ReloadJsonConfigs
-> _configs[attacker-controlled-or-missing-domain]
-> KeyNotFoundException
```
The arbitrary event injection and unhandled exception path are confirmed. Whether this terminates a dedicated server depends on Vintage Story's event/network exception policy, so a server-process crash is plausible but not established without detonation.
Evidence: [SendEvent and surrounding network code](G:/GameDev/Hostile/.codex-forensics/configlib_1.11.0_9e15e68a/decompiled/ConfigLib/ConfigLibModSystem.cs:169), [ReloadJsonConfigs](G:/GameDev/Hostile/.codex-forensics/configlib_1.11.0_9e15e68a/decompiled/ConfigLib/ConfigLibModSystem.cs:543).
### 9.2 High: configuration path escape, including server-controlled client paths
Configuration constructors combine `DataBasePath`, `ModConfig`, and a definition-supplied path without canonicalizing the result or verifying that it remains under `ModConfig`. On Windows, a rooted later component replaces the intended prefix, and `..\` segments traverse out of it.
Path values can originate from:
- installed mods' `configlib-patches.json` files;
- the public `RegisterCustomManagedConfig(..., path)` API;
- server-synchronized recipe-registry configuration definitions.
The server-to-client path is the meaningful trust-boundary issue. A malicious multiplayer server can supply `domain`/`jsonFile` data that the client passes to `Config` constructors. Under the game user's filesystem permissions:
- a crafted YAML domain can escape the intended directory and reaches an unconditional constructor-time write;
- a crafted JSON path can read, create, overwrite through normal saves, and watch an arbitrary path;
- nonexistent JSON targets are created with `{}`;
- non-JSON contents can be copied into verbose local parse-error logs.
ConfigLib does not contain a route that sends arbitrary file contents back to the server or over HTTP. This is unauthorized local read/write exposure and potential corruption, not confirmed exfiltration.
Evidence: [path construction](G:/GameDev/Hostile/.codex-forensics/configlib_1.11.0_9e15e68a/decompiled/ConfigLib/Config.cs:145), [read/write operations](G:/GameDev/Hostile/.codex-forensics/configlib_1.11.0_9e15e68a/decompiled/ConfigLib/Config.cs:759), [server registry deserialization](G:/GameDev/Hostile/.codex-forensics/configlib_1.11.0_9e15e68a/decompiled/ConfigLib/ConfigRegistry.cs:20).
### 9.3 Medium: malformed privileged setting packets
The ordinary server-setting handler correctly checks `Privilege.controlserver`, but subsequent JSON/value/mapping validation is incomplete. `ConfigSetting.MappingKey` indexes `Validation.Mapping` without checking that the supplied key exists. An invalid key can throw in server and client handlers. The server route requires the privilege, reducing exposure. A client-controlled `IsSinglePlayer` flag also suppresses the server's file write, which is an integrity/consistency defect.
### 9.4 Medium: unbounded registry and formula inputs
`ConfigRegistry.FromBytes` trusts server-supplied entry counts, lengths, definitions, and setting payloads without explicit local bounds or a surrounding catch. Game transport limits may impose practical caps, but ConfigLib itself does not.
Expression definitions are parsed recursively with no nesting-depth limit. A sufficiently deep hostile formula could cause a fatal stack overflow; ordinary parser errors are caught elsewhere, but a stack overflow is generally not recoverable. Wildcard asset patches can also repeatedly enumerate the full asset collection, providing a resource-exhaustion path with hostile definitions.
### 9.5 Medium/low: cleanup defects
`ConfigLibModSystem.Dispose()` calls `PauseMenuPatch.Patch()` again instead of the existing `PauseMenuPatch.Unpatch()`. This can leave or duplicate the Harmony prefix across unload/reload. The same defect is in public source and is more consistent with a bug than a second concealed payload.
Additional cleanup problems include:
- `GuiManager.Dispose()` does not clear its static instance or unregister its hotkey handler;
- a `Config.Dispose()` can dispose a directory-shared watcher and clear global path state used by other configs;
- disposed watcher entries remain in `_fileWatchers`, impairing later reload behavior.
Evidence: [Dispose](G:/GameDev/Hostile/.codex-forensics/configlib_1.11.0_9e15e68a/decompiled/ConfigLib/ConfigLibModSystem.cs:216), [PauseMenuPatch](G:/GameDev/Hostile/.codex-forensics/configlib_1.11.0_9e15e68a/decompiled/ConfigLib/Patches/PauseMenuPatch.cs:19).
### 9.6 Low/runtime-dependent GUI exception paths
- The mapping UI can index past an array when the current translated value is not found, unless ImGui clamps the selection.
- The color editor assumes a valid seven-character `#RRGGBB` value before substring/hex parsing.
- GUI draw callbacks do not have a broad exception boundary, so ultimate impact depends on VSImGui/game callback handling.
These are malformed-definition robustness issues, not hidden attack logic.
### 9.7 User-click link opening
Definitions may supply link strings. After a user clicks the corresponding UI control, ConfigLib passes the string to Vintage Story's `OpenLink` API without its own scheme/host allowlist. This is not automatic, and the underlying game API may enforce restrictions. It remains a social-engineering surface when definitions or servers are untrusted.
## 10. Bundled code present but not reached by ConfigLib
The merged assembly also contains generally powerful helper types. Static call-path searches found no ConfigLib construction or use of:
- `ReflectionContext`, which can access/invoke members on a supplied object;
- `StatsContext`, which can read player stats;
- `SettingsOrigin`, which reports that it may affect gameplay.
These are bundled/dead library capabilities in this assembly, not confirmed active behavior or a second payload.
## 11. Negative findings and scope boundary
An exhaustive high-risk API, IL, string, resource, and call-path review found no evidence in this exact archive of:
- `System.Net`, `HttpClient`, WebClient, DNS, TCP/UDP, raw socket, webhook, or command-and-control traffic;
- process creation, shell/PowerShell execution, process termination, `Environment.Exit`, or `FailFast`;
- registry access, services, scheduled tasks, startup entries, or other OS persistence;
- P/Invoke declarations, unmanaged injection, suspicious COM, or dynamic native-library loading;
- `Assembly.Load*`, reflection emit, runtime compilation, downloader, or updater behavior;
- credential/token/browser-wallet collection, clipboard capture, screenshots, or keylogging;
- hidden executable/script resources, encrypted/base64 second stages, or appended PNG content;
- file deletion, file encryption, direct world/save manipulation, or intentional save corruption.
Normal Vintage Story networking is used for ConfigLib synchronization, and user-clicked links can invoke the game's browser-opening API. The path-validation flaw can cause local reads/writes outside `ModConfig`; that is documented separately and must not be confused with the absence of a hardcoded file-destruction payload.
No second concealed malicious execution chain was found. The deliberately out-of-purpose code isolated in this release is:
- `AdditionalStuff.cs` / `YamlDotNet.Serialization.SettingsBuilder`;
- its module initializer and event subscription;
- its loaded-assembly/type/member scanners;
- its control-character, CRC-prefix, and 22% obfuscation detectors;
- its delayed callbacks and all internal `ClientMain` mutations;
- the otherwise unexplained `ConfigsChanged` event scaffold added with the ignore rule.
## 12. Indicators of compromise / detection
### Submitted artifact
- ZIP SHA-256: `9E15E68AA11723405BE02054FACFEEB08DD4499773D555E3889FDA62A9A89C50`
- ZIP SHA-1: `57739CA10804B50BE6ABB8528DFCAE6931892C37`
- ZIP MD5: `19CF93AD268777E2579423268CE50208`
- DLL SHA-256: `42EDF8D55423260038D6F1B61FC33515011D8EE9802AFB1B2E9F717C9FC710FC`
- DLL SHA-1: `2F742CD09CC7D77411FACE49747C74CCDAB329F7`
- PDB SHA-256: `9FAF53383ADBA9A8C1FBAEB9449DEAD1577E366AF001BDAFB808EE53EAE1A818`
- MVID: `de84b3c3-6ff7-4423-a5f0-bf72b0cf2707`
- Portable PDB ID: `D1CDC528A4C49FFFA5FE7A330794BEC5CE215845`
### Structural/static indicators
- hidden document: `AdditionalStuff.cs`
- hidden type: `YamlDotNet.Serialization.SettingsBuilder`
- method names: `Init`, `ConfigsChanged`, `GetSettings`, `GetSettingsValues`, `ReloadFromConfigs`
- initializer token: `0x0600024E`
- state-corruption method token: `0x06000251`
- field/method strings: `KillNextFrame`, `GuiComposers`, `ScreenRunningGame`, `LoadedEntities`, `PacketHandlers`, `SendLeave`
- CRC constants: `3606486923`, `3515110866`, `2049016528`, `2562349273`, `2667834024`, `3614613420`, `99783805`, `3708276016`
- repository marker: `*AdditionalStuff*`
- scaffold commit: `710f40d99e394aabfdb1f60fc5575461afc5f2dd`
Hash-only detection finds only exact builds. The structural indicators are better for variants.
## 13. Recommended long-term remediation
- Treat 1.10.9–1.12.0 as malicious/untrusted. Do not distribute or mirror them as functional releases.
- Restart affected game processes after removal; removing a file does not unload an assembly already resident in memory.
- Search all mod directories, launch profiles, server instances, download caches, and backups by both filename and hash.
- Do not designate 1.13.1 or a fork as trusted merely because this one class is absent. Require a clean whole-binary review, transparent source, reproducible build, and dependency verification.
- A trustworthy replacement should be rebuilt from reviewed source with genuine YamlDotNet rather than binary-patching this DLL.
- Fix the separate event allowlisting/privilege issue and canonicalize every config path before any read, write, or watcher creation.
- Bound registry entry counts/sizes and parser depth, validate mapping keys, and repair unload/watcher cleanup.
- For incident response, compare game logs around unexplained multiplayer failures occurring roughly 1.5–16 minutes after configuration loading or joining. Random timing/actions mean no single stack trace is definitive.
- No OS persistence was found, so removal and process restart address the known payload. Broader endpoint scanning remains reasonable if other untrusted mods were installed, but this sample alone does not establish a system-wide compromise.
## 14. Methodology and limitations
### Work performed
- preserved and hashed the original archive;
- validated ZIP structure, entries, CRCs, comments, flags, paths, and extra fields;
- extracted to an isolated analysis directory without loading the DLL;
- parsed PE/CLR metadata, sections, imports, signatures, resources, assembly references, and strings;
- decompiled all 321 generated source/project files and produced raw IL with sequence points;
- reviewed all 42 ConfigLib files, the hidden type, merged dependencies, high-risk APIs, network/file/process/reflection paths, and lifecycle/disposal code;
- parsed the portable PDB and extracted/hashed its embedded source;
- compared tracked sources with the public repository and genuine YamlDotNet;
- decoded and independently verified every CRC32 condition;
- statically sampled official releases for lineage and unrelated mods for false-positive breadth;
- independently cross-reviewed binary structure/provenance, malicious control flow, and remaining security-relevant behavior.
### Limitations
- The target was intentionally not detonated. Exact visible crash presentation across game versions was therefore not measured, although the triggering predicates and state writes are explicit in raw IL and original embedded source.
- Findings apply exactly to the hashes listed. Release-lineage conclusions apply to the additional official artifacts that were separately hashed and statically examined.
- A retracted 1.10.11 artifact was not recovered.
- “Not found” means absent from statically visible IL, metadata, strings, resources, and reachable call paths reviewed. No static method can prove the absence of every possible runtime interaction with external code.
- VSImGui, Vintage Story itself, and other external dependencies not bundled in this ZIP were outside the whole-code audit. Their APIs were inspected only as necessary to interpret calls.
- The two false-positive ratios are safe metadata approximations; exact reflection results include inherited members.
- The binary is unsigned, so publication/build provenance is strong but individual authorship is not cryptographically provable.
## Final assessment
ConfigLib 1.11.0 is not merely buggy. The official binary contains a conditional, delayed, randomized sabotage routine intentionally hidden from its public source and unrelated to its advertised configuration function. Its design specifically obscures causality while damaging multiplayer clients, and its generic obfuscation heuristic exposes unrelated mods to the same treatment. The appropriate disposition is quarantine/removal and replacement from a separately trusted codebase, not continued use with the offending feature disabled.
For immediate assistance, please email our customer support: [email protected]