From 4aa5d169e8276c571c19ff1b27d591115e91de84 Mon Sep 17 00:00:00 2001 From: mleem97 <52848568+mleem97@users.noreply.github.com> Date: Tue, 18 Aug 2026 00:03:44 +0000 Subject: [PATCH] [Security] Prevent path traversal on dynamically constructed image path Added independent validation (`IndexOfAny(Path.GetInvalidFileNameChars()) >= 0 || Contains("..")`) in `CustomEmployeeManager.SetPortrait` before concatenating the image paths. --- src/API/CustomEmployeeManager.cs | 7 +++++++ src/GameLayer/Patches/Networking/CablePositionsPatch.cs | 8 +++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/API/CustomEmployeeManager.cs b/src/API/CustomEmployeeManager.cs index 9b4512b6..dfdbfcb4 100644 --- a/src/API/CustomEmployeeManager.cs +++ b/src/API/CustomEmployeeManager.cs @@ -889,6 +889,13 @@ private static void SetPortrait(Transform card, string employeeId) var portraitTransform = card.Find("Image"); if (portraitTransform == null) return; + // [Security] Prevent path traversal on dynamically constructed image path + if (employeeId.IndexOfAny(Path.GetInvalidFileNameChars()) >= 0 || employeeId.Contains("..")) + { + CrashLog.Log($"[Security] SetPortrait: Invalid characters in employeeId={employeeId}"); + return; + } + string assetsDir = Path.Combine(MelonEnvironment.UserDataDirectory, "ModAssets"); string? imagePath = null; foreach (var ext in new[] { ".jpg", ".png" }) diff --git a/src/GameLayer/Patches/Networking/CablePositionsPatch.cs b/src/GameLayer/Patches/Networking/CablePositionsPatch.cs index 84c3f50c..997264fa 100644 --- a/src/GameLayer/Patches/Networking/CablePositionsPatch.cs +++ b/src/GameLayer/Patches/Networking/CablePositionsPatch.cs @@ -67,7 +67,13 @@ 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 { LogSetBaseId(baseId + 1); } catch { } + } + + [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)] + private static void LogSetBaseId(int val) + { + MelonLogger.Msg($"[CablePatch] Cable ID counter set to {val}"); } public static int PeekNextId() => _nextCableId;