diff --git a/CHANGELOG.md b/CHANGELOG.md index 4c94d0513..8c5ead4c7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,15 @@ All notable changes to Stability Matrix will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning 2.0](https://semver.org/spec/v2.0.0.html). +## v2.13.2 +### Changed +- Removed SimpleSDXL due to security concerns - thanks to @iwr-redmond for the detailed report. For more information please visit https://github.com/LykosAI/StabilityMatrix/security/advisories. +### Supporters +#### Visionaries +- Many thanks to our amazing Visionary-tier Patrons, **Waterclouds** and **TheTekknician**! Your support is greatly appreciated! +#### Pioneers +- Shoutout to our Pioneer-tier Patrons, **tankfox**, **Mr. Unknown**, **Szir777**, **Tigon**, and **NowFallenAngel**! Thank you for your continued support! + ## v2.13.1 ### Changed - Redesigned the Checkpoint Manager Filter flyout to include more options and improve the layout diff --git a/StabilityMatrix.Avalonia/Services/RunningPackageService.cs b/StabilityMatrix.Avalonia/Services/RunningPackageService.cs index 641ff82e1..00b736dab 100644 --- a/StabilityMatrix.Avalonia/Services/RunningPackageService.cs +++ b/StabilityMatrix.Avalonia/Services/RunningPackageService.cs @@ -1,15 +1,13 @@ -using System; -using System.Collections.Generic; -using System.Collections.Immutable; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; +using System.Collections.Immutable; using Avalonia.Controls.Notifications; +using Avalonia.Threading; using CommunityToolkit.Mvvm.ComponentModel; +using FluentAvalonia.UI.Controls; using Injectio.Attributes; using KeyedSemaphores; using Microsoft.Extensions.Logging; using Nito.Disposables.Internals; +using StabilityMatrix.Avalonia.Languages; using StabilityMatrix.Avalonia.Models; using StabilityMatrix.Avalonia.ViewModels; using StabilityMatrix.Core.Extensions; @@ -79,6 +77,111 @@ IPyRunner pyRunner return null; } + // Show warning if critical vulnerabilities are found + if (basePackage.HasCriticalVulnerabilities) + { + var vulns = basePackage + .KnownVulnerabilities.Where(v => v.Severity == VulnerabilitySeverity.Critical) + .Select( + v => + $"**{v.Id}**: {v.Title}\n - Severity: {v.Severity}\n - Description: {v.Description}" + ) + .ToList(); + + var message = + $"# ⚠️ Critical Security Vulnerabilities\n\nThis package has critical security vulnerabilities that may put your system at risk:\n\n{string.Join("\n\n", vulns)}"; + message += + "\n\nFor more information, please visit the [GitHub Security Advisory page](https://github.com/LykosAI/StabilityMatrix/security/advisories)."; + + var dialog = DialogHelper.CreateMarkdownDialog(message, "Security Warning"); + + dialog.IsPrimaryButtonEnabled = false; + dialog.PrimaryButtonText = "Continue Anyway (3)"; + dialog.CloseButtonText = Resources.Action_Cancel; + dialog.DefaultButton = ContentDialogButton.Close; + + // Start a timer to enable the button after 3 seconds + var countdown = 3; + var timer = new System.Timers.Timer(1000); + timer.Elapsed += (_, _) => + { + Dispatcher.UIThread.Post(() => + { + countdown--; + if (countdown <= 0) + { + dialog.IsPrimaryButtonEnabled = true; + dialog.PrimaryButtonText = "Continue Anyway"; + timer.Stop(); + timer.Dispose(); + } + else + { + dialog.PrimaryButtonText = $"Continue Anyway ({countdown})"; + } + }); + }; + timer.Start(); + + var result = await dialog.ShowAsync(); + if (result != ContentDialogResult.Primary) + { + return null; + } + } + // Show warning if any vulnerabilities are found + else if (basePackage.HasVulnerabilities) + { + var vulns = basePackage + .KnownVulnerabilities.Select( + v => + $"**{v.Id}**: {v.Title}\n - Severity: {v.Severity}\n - Description: {v.Description}" + ) + .ToList(); + + var message = + $"# ⚠️ Security Notice\n\nThis package has known vulnerabilities:\n\n{string.Join("\n\n", vulns)}"; + + message += + "\n\nFor more information, please visit the [GitHub Security Advisory page](https://github.com/LykosAI/StabilityMatrix/security/advisories)."; + + var dialog = DialogHelper.CreateMarkdownDialog(message, "Security Notice"); + + dialog.IsPrimaryButtonEnabled = false; + dialog.PrimaryButtonText = "Continue Anyway (3)"; + dialog.CloseButtonText = Resources.Action_Cancel; + dialog.DefaultButton = ContentDialogButton.Close; + + // Start a timer to enable the button after 3 seconds + var countdown = 3; + var timer = new System.Timers.Timer(1000); + timer.Elapsed += (_, _) => + { + Dispatcher.UIThread.Post(() => + { + countdown--; + if (countdown <= 0) + { + dialog.IsPrimaryButtonEnabled = true; + dialog.PrimaryButtonText = "Continue Anyway"; + timer.Stop(); + timer.Dispose(); + } + else + { + dialog.PrimaryButtonText = $"Continue Anyway ({countdown})"; + } + }); + }; + timer.Start(); + + var result = await dialog.ShowAsync(); + if (result != ContentDialogResult.Primary) + { + return null; + } + } + // If this is the first launch (LaunchArgs is null), // load and save a launch options dialog vm // so that dynamic initial values are saved. diff --git a/StabilityMatrix.Core/Helper/Factory/PackageFactory.cs b/StabilityMatrix.Core/Helper/Factory/PackageFactory.cs index e160524b8..341790ffc 100644 --- a/StabilityMatrix.Core/Helper/Factory/PackageFactory.cs +++ b/StabilityMatrix.Core/Helper/Factory/PackageFactory.cs @@ -102,7 +102,10 @@ public BasePackage GetNewBasePackage(InstalledPackage installedPackage) public IEnumerable GetAllAvailablePackages() { - return basePackages.Values.OrderBy(p => p.InstallerSortOrder).ThenBy(p => p.DisplayName); + return basePackages + .Values.Where(p => !p.HasVulnerabilities) + .OrderBy(p => p.InstallerSortOrder) + .ThenBy(p => p.DisplayName); } public BasePackage? FindPackageByName(string? packageName) diff --git a/StabilityMatrix.Core/Models/Packages/BasePackage.cs b/StabilityMatrix.Core/Models/Packages/BasePackage.cs index 7c58cd485..2f5f80a7f 100644 --- a/StabilityMatrix.Core/Models/Packages/BasePackage.cs +++ b/StabilityMatrix.Core/Models/Packages/BasePackage.cs @@ -267,4 +267,30 @@ protected Task InstallCpuTorch( } public abstract Task GetUpdate(InstalledPackage installedPackage); + + /// + /// List of known vulnerabilities for this package + /// + public virtual IReadOnlyList KnownVulnerabilities { get; protected set; } = + Array.Empty(); + + /// + /// Whether this package has any known vulnerabilities + /// + public bool HasVulnerabilities => KnownVulnerabilities.Any(); + + /// + /// Whether this package has any critical vulnerabilities + /// + public bool HasCriticalVulnerabilities => + KnownVulnerabilities.Any(v => v.Severity == VulnerabilitySeverity.Critical); + + /// + /// Check for any new vulnerabilities from external sources + /// + public virtual Task CheckForVulnerabilities(CancellationToken cancellationToken = default) + { + // Base implementation does nothing - derived classes should implement their own vulnerability checking + return Task.CompletedTask; + } } diff --git a/StabilityMatrix.Core/Models/Packages/PackageVulnerability.cs b/StabilityMatrix.Core/Models/Packages/PackageVulnerability.cs new file mode 100644 index 000000000..313bc6a70 --- /dev/null +++ b/StabilityMatrix.Core/Models/Packages/PackageVulnerability.cs @@ -0,0 +1,60 @@ +using System; + +namespace StabilityMatrix.Core.Models.Packages; + +/// +/// Represents a security vulnerability in a package +/// +public class PackageVulnerability +{ + /// + /// Unique identifier for the vulnerability (e.g. CVE number) + /// + public string Id { get; set; } = string.Empty; + + /// + /// Short title describing the vulnerability + /// + public string Title { get; set; } = string.Empty; + + /// + /// Detailed description of the vulnerability + /// + public string Description { get; set; } = string.Empty; + + /// + /// URL with more information about the vulnerability + /// + public Uri? InfoUrl { get; set; } + + /// + /// Severity level of the vulnerability + /// + public VulnerabilitySeverity Severity { get; set; } + + /// + /// When this vulnerability was discovered/published + /// + public DateTimeOffset PublishedDate { get; set; } + + /// + /// Version ranges affected by this vulnerability + /// + public string[] AffectedVersions { get; set; } = Array.Empty(); + + /// + /// Version that fixes this vulnerability, if available + /// + public string? FixedInVersion { get; set; } +} + +/// +/// Severity levels for package vulnerabilities +/// +public enum VulnerabilitySeverity +{ + Low, + Medium, + High, + Critical +} diff --git a/StabilityMatrix.Core/Models/Packages/SimpleSDXL.cs b/StabilityMatrix.Core/Models/Packages/SimpleSDXL.cs index 6587b6f7b..28b80caf1 100644 --- a/StabilityMatrix.Core/Models/Packages/SimpleSDXL.cs +++ b/StabilityMatrix.Core/Models/Packages/SimpleSDXL.cs @@ -33,6 +33,27 @@ IPrerequisiteHelper prerequisiteHelper public override IEnumerable AvailableTorchIndices => [TorchIndex.Cuda]; public override bool IsCompatible => HardwareHelper.HasNvidiaGpu(); + public override IReadOnlyList KnownVulnerabilities => + [ + new() + { + Id = "GHSA-qq8j-phpf-c63j", + Title = "Undisclosed Data Collection and Remote Access in simpleai_base Dependency", + Description = + "SimpleSDXL depends on simpleai_base which contains compiled Rust code with:\n" + + "- Undisclosed remote access functionality using rathole\n" + + "- Hidden system information gathering via concealed executable calls\n" + + "- Covert data upload to tokentm.net (blockchain-associated domain)\n" + + "- Undisclosed VPN functionality pointing to servers blocked by Chinese authorities\n\n" + + "This poses significant security and privacy risks as system information is uploaded without consent " + + "and the compiled nature of the code means the full extent of the remote access capabilities cannot be verified.", + Severity = VulnerabilitySeverity.Critical, + PublishedDate = DateTimeOffset.Parse("2025-01-11"), + InfoUrl = new Uri("https://github.com/metercai/SimpleSDXL/issues/97"), + AffectedVersions = ["*"], // Affects all versions + } + ]; + public override List LaunchOptions => [ new()