From 3271910cdb17a5f48415526bc7b89a9a9e63663a Mon Sep 17 00:00:00 2001 From: mleem97 <52848568+mleem97@users.noreply.github.com> Date: Fri, 7 Aug 2026 00:03:04 +0000 Subject: [PATCH 1/2] Sentinel: Fix path traversal in SetPortrait --- src/API/CustomEmployeeManager.cs | 13 ++++++++++--- .../Patches/Networking/CablePositionsPatch.cs | 15 ++++++++++++++- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/src/API/CustomEmployeeManager.cs b/src/API/CustomEmployeeManager.cs index 9b4512b6..df8c5e42 100644 --- a/src/API/CustomEmployeeManager.cs +++ b/src/API/CustomEmployeeManager.cs @@ -891,10 +891,17 @@ private static void SetPortrait(Transform card, string employeeId) string assetsDir = Path.Combine(MelonEnvironment.UserDataDirectory, "ModAssets"); string? imagePath = null; - foreach (var ext in new[] { ".jpg", ".png" }) + + // [Security] Prevent path traversal from unsanitized employeeId + if (!string.IsNullOrEmpty(employeeId) && + employeeId.IndexOfAny(Path.GetInvalidFileNameChars()) < 0 && + !employeeId.Contains("..")) { - string candidate = Path.Combine(assetsDir, employeeId + ext); - if (File.Exists(candidate)) { imagePath = candidate; break; } + foreach (var ext in new[] { ".jpg", ".png" }) + { + string candidate = Path.Combine(assetsDir, employeeId + ext); + if (File.Exists(candidate)) { imagePath = candidate; break; } + } } if (imagePath != null) diff --git a/src/GameLayer/Patches/Networking/CablePositionsPatch.cs b/src/GameLayer/Patches/Networking/CablePositionsPatch.cs index 84c3f50c..cd909f7d 100644 --- a/src/GameLayer/Patches/Networking/CablePositionsPatch.cs +++ b/src/GameLayer/Patches/Networking/CablePositionsPatch.cs @@ -57,6 +57,12 @@ private static bool CreateNewCablePrefix( } } + [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)] + private static void LogBaseIdChange(int baseId) + { + MelonLogger.Msg($"[CablePatch] Cable ID counter set to {baseId + 1}"); + } + public static void SetBaseId(int baseId) { int current; @@ -67,7 +73,14 @@ public static void SetBaseId(int baseId) } while (Interlocked.CompareExchange(ref _nextCableId, baseId + 1, current) != current); - MelonLogger.Msg($"[CablePatch] Cable ID counter set to {baseId + 1}"); + try + { + LogBaseIdChange(baseId); + } + catch (System.Exception) + { + // Ignore MelonLoader not being present in test environment + } } public static int PeekNextId() => _nextCableId; From 79016b379fa15f65666b19f9d25c0248974c8201 Mon Sep 17 00:00:00 2001 From: mleem97 <52848568+mleem97@users.noreply.github.com> Date: Fri, 7 Aug 2026 00:05:08 +0000 Subject: [PATCH 2/2] Sentinel: Fix path traversal in SetPortrait