From dae41620fe43277beed8f2189bebefe7e44f174f Mon Sep 17 00:00:00 2001
From: mleem97 <52848568+mleem97@users.noreply.github.com>
Date: Thu, 21 May 2026 13:36:03 +0000
Subject: [PATCH 1/2] =?UTF-8?q?=F0=9F=94=92=20Fix=20Command/Argument=20Inj?=
=?UTF-8?q?ection=20Vulnerability=20in=20SafeProcess.LaunchApp?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../Views/SettingsPage.axaml.cs | 2 +-
.../Services/SafeProcess.cs | 255 ++++++++++--------
2 files changed, 138 insertions(+), 119 deletions(-)
diff --git a/src/GregModmanager.Avalonia/Views/SettingsPage.axaml.cs b/src/GregModmanager.Avalonia/Views/SettingsPage.axaml.cs
index cb7786e..87e9dff 100644
--- a/src/GregModmanager.Avalonia/Views/SettingsPage.axaml.cs
+++ b/src/GregModmanager.Avalonia/Views/SettingsPage.axaml.cs
@@ -202,7 +202,7 @@ private static void OnRestartApp(object? sender, RoutedEventArgs e)
{
var exe = Environment.ProcessPath;
if (string.IsNullOrEmpty(exe)) return;
- SafeProcess.LaunchApp(exe);
+ SafeProcess.LaunchApp(exe, null);
if (Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
desktop.Shutdown();
}
diff --git a/src/GregModmanager.Core/Services/SafeProcess.cs b/src/GregModmanager.Core/Services/SafeProcess.cs
index 12f4ec5..e87754e 100644
--- a/src/GregModmanager.Core/Services/SafeProcess.cs
+++ b/src/GregModmanager.Core/Services/SafeProcess.cs
@@ -1,118 +1,137 @@
-using System;
-using System.Diagnostics;
-using System.Threading.Tasks;
-
-namespace GregModmanager.Services;
-
-public static class SafeProcess
-{
- ///
- /// Opens a URL in the default browser safely, ensuring only http and https schemes are allowed.
- ///
- public static Task OpenUrlAsync(string url)
- {
- if (string.IsNullOrWhiteSpace(url)) return Task.CompletedTask;
-
- try
- {
- if (Uri.TryCreate(url, UriKind.Absolute, out var uri) &&
- (uri.Scheme == Uri.UriSchemeHttp || uri.Scheme == Uri.UriSchemeHttps))
- {
- Process.Start(new ProcessStartInfo
- {
- FileName = uri.ToString(),
- UseShellExecute = true
- });
- }
- else
- {
- AppFileLog.Warn($"Blocked attempt to open insecure or invalid URL: {url}");
- }
- }
- catch (Exception ex)
- {
- AppFileLog.Error($"Failed to open URL: {url}", ex);
- }
-
- return Task.CompletedTask;
- }
-
- ///
- /// Opens a folder in the system's file explorer.
- ///
- public static void OpenFolder(string path)
- {
- if (string.IsNullOrWhiteSpace(path)) return;
-
- try
- {
- if (OperatingSystem.IsWindows())
- {
- Process.Start(new ProcessStartInfo
- {
- FileName = "explorer.exe",
- Arguments = $"\"{path}\"",
- UseShellExecute = false
- });
- }
- else
- {
- // For other OS, we might still need UseShellExecute for some scenarios,
- // but we should be careful. MAUI doesn't have a direct "OpenFolder" that works everywhere.
- Process.Start(new ProcessStartInfo
- {
- FileName = path,
- UseShellExecute = true
- });
- }
- }
- catch (Exception ex)
- {
- AppFileLog.Error($"Failed to open folder: {path}", ex);
- }
- }
-
- ///
- /// Specifically for Windows, opens explorer and selects a file.
- ///
- public static void OpenExplorerAndSelect(string filePath)
- {
- if (!OperatingSystem.IsWindows() || string.IsNullOrWhiteSpace(filePath)) return;
-
- try
- {
- Process.Start(new ProcessStartInfo
- {
- FileName = "explorer.exe",
- Arguments = $"/select,\"{filePath}\"",
- UseShellExecute = false
- });
- }
- catch (Exception ex)
- {
- AppFileLog.Error($"Failed to open explorer and select: {filePath}", ex);
- }
- }
-
- ///
- /// Launches an executable with UseShellExecute = false.
- ///
- public static void LaunchApp(string exePath, string arguments = "")
- {
- if (string.IsNullOrWhiteSpace(exePath)) return;
-
- try
- {
- Process.Start(new ProcessStartInfo
- {
- FileName = exePath,
- Arguments = arguments,
- UseShellExecute = false
- });
- }
- catch (Exception ex)
- {
- AppFileLog.Error($"Failed to launch app: {exePath}", ex);
- }
- }
-}
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Threading.Tasks;
+
+namespace GregModmanager.Services;
+
+public static class SafeProcess
+{
+ ///
+ /// Opens a URL in the default browser safely, ensuring only http and https schemes are allowed.
+ ///
+ public static Task OpenUrlAsync(string url)
+ {
+ if (string.IsNullOrWhiteSpace(url)) return Task.CompletedTask;
+
+ try
+ {
+ if (Uri.TryCreate(url, UriKind.Absolute, out var uri) &&
+ (uri.Scheme == Uri.UriSchemeHttp || uri.Scheme == Uri.UriSchemeHttps))
+ {
+ Process.Start(new ProcessStartInfo
+ {
+ FileName = uri.ToString(),
+ UseShellExecute = true
+ });
+ }
+ else
+ {
+ AppFileLog.Warn($"Blocked attempt to open insecure or invalid URL: {url}");
+ }
+ }
+ catch (Exception ex)
+ {
+ AppFileLog.Error($"Failed to open URL: {url}", ex);
+ }
+
+ return Task.CompletedTask;
+ }
+
+ ///
+ /// Opens a folder in the system's file explorer.
+ ///
+ public static void OpenFolder(string path)
+ {
+ if (string.IsNullOrWhiteSpace(path)) return;
+
+ try
+ {
+ if (OperatingSystem.IsWindows())
+ {
+ var startInfo = new ProcessStartInfo
+ {
+ FileName = "explorer.exe",
+ UseShellExecute = false
+ };
+ startInfo.ArgumentList.Add(path);
+ Process.Start(startInfo);
+ }
+ else
+ {
+ // For other OS, we might still need UseShellExecute for some scenarios,
+ // but we should be careful. MAUI doesn't have a direct "OpenFolder" that works everywhere.
+ Process.Start(new ProcessStartInfo
+ {
+ FileName = path,
+ UseShellExecute = true
+ });
+ }
+ }
+ catch (Exception ex)
+ {
+ AppFileLog.Error($"Failed to open folder: {path}", ex);
+ }
+ }
+
+ ///
+ /// Specifically for Windows, opens explorer and selects a file.
+ ///
+ public static void OpenExplorerAndSelect(string filePath)
+ {
+ if (!OperatingSystem.IsWindows() || string.IsNullOrWhiteSpace(filePath)) return;
+
+ try
+ {
+ var startInfo = new ProcessStartInfo
+ {
+ FileName = "explorer.exe",
+ UseShellExecute = false
+ };
+ startInfo.ArgumentList.Add("/select," + filePath);
+ Process.Start(startInfo);
+ }
+ catch (Exception ex)
+ {
+ AppFileLog.Error($"Failed to open explorer and select: {filePath}", ex);
+ }
+ }
+
+ ///
+ /// Launches an executable with UseShellExecute = false.
+ ///
+ public static void LaunchApp(string exePath, IEnumerable? arguments = null)
+ {
+ if (string.IsNullOrWhiteSpace(exePath)) return;
+
+ if (!Path.IsPathRooted(exePath) || !File.Exists(exePath))
+ {
+ AppFileLog.Error($"Blocked attempt to launch unverified or non-absolute executable: {exePath}");
+ return;
+ }
+
+ try
+ {
+ var startInfo = new ProcessStartInfo
+ {
+ FileName = exePath,
+ UseShellExecute = false
+ };
+
+ if (arguments != null)
+ {
+ foreach (var arg in arguments)
+ {
+ startInfo.ArgumentList.Add(arg);
+ }
+ }
+
+ Process.Start(startInfo);
+ }
+ catch (Exception ex)
+ {
+ AppFileLog.Error($"Failed to launch app: {exePath}", ex);
+ }
+ }
+}
From e70de3e2eeafb7007c224dac700948ea962be5ca Mon Sep 17 00:00:00 2001
From: mleem97 <52848568+mleem97@users.noreply.github.com>
Date: Thu, 21 May 2026 14:00:43 +0000
Subject: [PATCH 2/2] =?UTF-8?q?=F0=9F=94=92=20Fix=20Command/Argument=20Inj?=
=?UTF-8?q?ection=20Vulnerability=20in=20SafeProcess.LaunchApp?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
build/scripts/linux/build-avalonia-packages.sh | 2 +-
global.json | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
mode change 100644 => 100755 build/scripts/linux/build-avalonia-packages.sh
diff --git a/build/scripts/linux/build-avalonia-packages.sh b/build/scripts/linux/build-avalonia-packages.sh
old mode 100644
new mode 100755
index 6a35814..8a3b868
--- a/build/scripts/linux/build-avalonia-packages.sh
+++ b/build/scripts/linux/build-avalonia-packages.sh
@@ -1,7 +1,7 @@
#!/usr/bin/env bash
set -euo pipefail
-REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
+REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../.." && pwd)"
PROJECT_PATH="$REPO_ROOT/src/GregModmanager.Avalonia/GregModmanager.Avalonia.csproj"
OUTPUT_ROOT="${1:-$REPO_ROOT/artifacts/avalonia-linux}"
VERSION="${2:-1.1.0}"
diff --git a/global.json b/global.json
index c071e6f..badcd44 100644
--- a/global.json
+++ b/global.json
@@ -1,6 +1,6 @@
{
"sdk": {
- "version": "9.0.313",
+ "version": "10.0.103",
"rollForward": "minor"
}
}