Skip to content

Commit 8489cc6

Browse files
committed
docs: update CHANGELOG and ROADMAP after security hardening pass (10 items shipped)
1 parent 0bc2e71 commit 8489cc6

2 files changed

Lines changed: 40 additions & 117 deletions

File tree

CHANGELOG.md

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,23 @@ All notable changes to DeepPurge will be documented in this file.
1717
- **Screen-reader narration**`AutomationProperties.Name` and `.HelpText` on all v0.9 SYSTEM TOOLS panels (drivers, startup impact, shortcuts, duplicates, winapp2, repair, schedule, install monitor, about).
1818
- **Localization infrastructure**`Properties/Resources.resx` with top 20 UI strings and a strongly-typed `Resources.Designer.cs` accessor. Ready for Crowdin submission.
1919

20+
### Security hardening (research round 2)
21+
- **CVE-2025-30399 mitigation**`TargetLatestRuntimePatch` enabled via `Directory.Build.props` to pin .NET runtime ≥8.0.17.
22+
- **DuplicateFinder thread-safety** — replaced `Dictionary` with `ConcurrentDictionary` for hash cache to prevent data corruption under concurrent scans.
23+
- **Symlink/junction traversal guards** — all recursive deletion paths in FileLeftoverScanner, JunkFilesCleaner, and EvidenceRemover now check `FileAttributes.ReparsePoint` before traversal. `GetDirectorySize` uses `EnumerationOptions.AttributesToSkip`.
24+
- **Registry symlink detection**`SafetyGuard.IsRegistrySymlink()` checks for `REG_LINK` class before any registry write/delete in UninstallEngine. Prevents TOCTOU privilege escalation via registry symbolic links.
25+
- **NuGet supply chain hardening**`packages.lock.json` generated for all projects, CI uses `--locked-mode`, NuGet audit enabled at `moderate` level, package source mapping in `NuGet.Config`.
26+
- **Silent catch logging** — 22 empty `catch { }` blocks in RegistryLeftoverScanner replaced with `Log.Warn()` calls for field debugging.
27+
- **ManagementObject disposal** — WMI `ManagementObject` instances in SystemRestoreManager and SecureDelete now properly disposed via `using`.
28+
- **Always-keep protection**`ProtectedPrograms` persisted list excludes marked programs from batch uninstall. `IsProtected` flag on `InstalledProgram`.
29+
- **External signature loading**`LeftoverSignatureDb` now loads `*.signatures.json` files from `DataPaths.Cleaners` alongside the embedded database for community contributions.
30+
- **Toast notification migration** — replaced deprecated `Microsoft.Toolkit.Uwp.Notifications` with direct WinRT `Windows.UI.Notifications` API. Removes transitive `System.Drawing.Common` 4.7.0 vulnerability.
31+
2032
### Changed
2133
- TFM updated from `net8.0-windows` to `net8.0-windows10.0.17763.0` across all 4 projects to enable WinRT toast notification APIs.
2234

2335
### Dependencies
24-
- New: `Microsoft.Toolkit.Uwp.Notifications 7.1.3`Windows 10/11 toast notifications.
36+
- Removed: `Microsoft.Toolkit.Uwp.Notifications 7.1.3`deprecated, replaced with WinRT API.
2537

2638
### Research-driven additions (competitive analysis pass)
2739
- **Leftover signature database** — embedded JSON database with 50 application profiles (Chrome, Firefox, Adobe, Steam, etc.) for known leftover paths. Signature-matched leftovers are flagged as Safe confidence before heuristic matching runs.

ROADMAP.md

Lines changed: 27 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,11 @@ Blocked items live in `Roadmap_Blocked.md`.
1414
Acceptance: Scan detects orphaned services (exe missing), orphaned tasks (action exe missing), firewall rules referencing deleted programs, and PATH entries pointing to non-existent directories. Results shown in a unified "Orphans" panel.
1515
Complexity: L
1616

17-
- [ ] P1 — **Upgrade to .NET 9 + CommunityToolkit.Mvvm 8.4.2**
18-
Why: .NET 9 brings SearchValues SIMD acceleration for path scanning, FrozenDictionary for lookup tables, native WPF Fluent theme. Toolkit 8.4.2 adds partial properties — eliminates magic field pattern.
19-
Evidence: .NET 9 release notes; CommunityToolkit 8.4 announcement; System.IO.Hashing 9.0.13 SIMD optimizations.
20-
Touches: All 4 `.csproj` files (TFM `net9.0-windows10.0.17763.0`), `CommunityToolkit.Mvvm` → 8.4.2, `System.IO.Hashing`9.0.13, ViewModels (partial property migration)
21-
Acceptance: Build succeeds on net9.0, all 111+ tests pass, ViewModels use `[ObservableProperty] public partial` syntax.
17+
- [ ] P1 — **Target .NET 10 LTS + CommunityToolkit.Mvvm 8.4.2**
18+
Why: .NET 8 EOL Nov 2026. .NET 10 is LTS through Nov 2028. Toolkit 8.4.2 adds partial properties. Includes SearchValues SIMD, FrozenDictionary, native WPF Fluent theme.
19+
Evidence: .NET 10 release notes; .NET 9 STS EOL Nov 2026; breaking changes audit.
20+
Touches: All 4 `.csproj` files (TFM `net10.0-windows10.0.17763.0`), `CommunityToolkit.Mvvm` → 8.4.2, `System.IO.Hashing`10.0.9, ViewModels (partial property migration)
21+
Acceptance: Build succeeds on net10.0, all tests pass, ViewModels use `[ObservableProperty] public partial` syntax.
2222
Complexity: M
2323

2424
- [ ] P1 — **CsWin32 type-safe PInvoke**
@@ -42,10 +42,24 @@ Blocked items live in `Roadmap_Blocked.md`.
4242
Acceptance: User clicks "Hunter Mode" → overlay appears → drag crosshair onto any window → program identified → jump to its entry in the Programs panel.
4343
Complexity: M
4444

45+
- [ ] P1 — **Expand leftover signature database to 200+ profiles**
46+
Why: Current 50 profiles cover common apps but benchmark accuracy requires broader coverage. Target: ≥85% accuracy in Uninstalr benchmark.
47+
Evidence: Uninstalr 2026 benchmark — HiBit 90%, Total Uninstall 86%; Revo Logs Database covers 12.5k programs. Also fix: duplicate Spotify entry.
48+
Touches: `Core/Data/leftover-signatures.json`, `Core/Data/LeftoverSignatureDb.cs`
49+
Acceptance: 200+ profiles. Matching algorithm enhanced to handle publisher-based grouping. Duplicate Spotify entry removed.
50+
Complexity: M
51+
52+
- [ ] P1 — **Portable app detection**
53+
Why: Only Uninstalr detects portable apps. All 8 other tested tools scored 0. Significant unmet demand.
54+
Evidence: Uninstalr 2026 benchmark — portable app detection section; BCU's folder scan concept.
55+
Touches: New `Core/Packages/PortableAppScanner.cs`, `Core/Packages/PackageManagerScanner.cs`
56+
Acceptance: Scan common portable locations for executables without matching registry entries. Show as "Portable" source in program list.
57+
Complexity: M
58+
4559
### P2 — Quality, reliability, developer experience
4660

4761
- [ ] P2 — **Mutation testing on safety-critical code**
48-
Why: 111 tests for 15.8k LOC is thin. SafetyGuard and deletion logic are safety-critical — need verification that tests actually catch regressions.
62+
Why: 116 tests for ~14k LOC is thin. SafetyGuard and deletion logic are safety-critical — need verification that tests actually catch regressions.
4963
Evidence: Stryker.NET 4.14.2; mutation testing best practice for safety-critical paths.
5064
Touches: `tests/`, `.github/workflows/build.yml`
5165
Acceptance: Stryker runs in CI on `SafetyGuard.cs`, `SecureDelete.cs`, `UninstallEngine.cs`. Mutation score >80% on these files.
@@ -65,6 +79,13 @@ Blocked items live in `Roadmap_Blocked.md`.
6579
Acceptance: New sidebar panel with checkboxes for ~15 removable Windows components. Each shows current size. Delete through SafetyGuard with dry-run support.
6680
Complexity: S
6781

82+
- [ ] P2 — **winget COM API migration**
83+
Why: `winget list --output json` is not a supported CLI option. The `Microsoft.Management.Deployment` COM API is the official programmatic interface.
84+
Evidence: microsoft/winget-cli#4965 (feature request still open); winget export uses schema 2.0 JSON.
85+
Touches: `Core/Packages/PackageManagerScanner.cs`
86+
Acceptance: Use `winget export` for JSON package list or COM API for real-time queries. Remove `ParseWingetTable` fallback.
87+
Complexity: M
88+
6889
### P3 — Polish, differentiation
6990

7091
- [ ] P3 — **Health dashboard**
@@ -88,114 +109,6 @@ Blocked items live in `Roadmap_Blocked.md`.
88109
Acceptance: Steam (libraryfolders.vdf), Epic (LauncherInstalled.dat), GOG (Galaxy DB) apps appear in the unified programs list with platform badges.
89110
Complexity: M
90111

91-
## Research-Driven Additions (Round 2)
92-
93-
### P0 — Security hardening (act now)
94-
95-
- [ ] P0 — **Pin .NET runtime ≥8.0.17 for CVE-2025-30399**
96-
Why: Untrusted search path RCE affects .NET 8.0 ≤8.0.16. DeepPurge runs elevated — this is a privilege escalation vector.
97-
Evidence: NVD CVE-2025-30399 (CVSS 7.5); .NET security advisory June 2025.
98-
Touches: All 4 `.csproj` files — add `<RuntimeFrameworkVersion>8.0.17</RuntimeFrameworkVersion>` or target net10.0
99-
Acceptance: `dotnet --info` shows runtime 8.0.17+. CI build pins the minimum version.
100-
Complexity: S
101-
102-
- [ ] P0 — **Fix DuplicateFinder._cache thread-safety**
103-
Why: `_cache` dictionary at `Core/FileSystem/DuplicateFinder.cs:41` is accessed without synchronization. Concurrent `FindAsync` calls corrupt the cache.
104-
Evidence: Code review — `Dictionary<string, HashCacheEntry>` with no lock around reads/writes in TryGetCachedHead, TryGetCachedFull, UpdateCache.
105-
Touches: `Core/FileSystem/DuplicateFinder.cs`
106-
Acceptance: Replace `Dictionary` with `ConcurrentDictionary` or add lock around all cache access. Verify with concurrent scan test.
107-
Complexity: S
108-
109-
- [ ] P0 — **Symlink/junction traversal guard in deletion paths**
110-
Why: File deletion in FileLeftoverScanner, JunkFilesCleaner, EvidenceRemover does not check for reparse points before recursive deletion. BleachBit shipped a CVE-class fix for this exact pattern. DuplicateFinder.SafeEnumerate already has the guard but other scanners don't.
111-
Evidence: BleachBit 6.0 release notes (symlink/junction safety); FluentCleaner reparse point skip.
112-
Touches: `Core/FileSystem/FileLeftoverScanner.cs`, `Core/FileSystem/JunkFilesCleaner.cs`, `Core/Privacy/EvidenceRemover.cs`
113-
Acceptance: All recursive directory deletion checks `FileAttributes.ReparsePoint` before traversal. Add test with a junction-loop directory structure.
114-
Complexity: S
115-
116-
- [ ] P0 — **Registry symlink detection before writes**
117-
Why: Elevated process writes to enumerated registry keys without checking for symlinks. Unprivileged attacker can redirect writes to critical system keys via registry symbolic links. CVE-2025-6231 and CVE-2026-20815 exploited this exact pattern.
118-
Evidence: Security research — registry TOCTOU privilege escalation; Project Zero Windows Administrator Protection bypass.
119-
Touches: `Core/Registry/RegistryLeftoverScanner.cs`, `Core/Uninstall/UninstallEngine.cs`
120-
Acceptance: Before any registry write/delete, verify key is not a symlink (REG_LINK class check). Fail-closed: if check fails, skip the key and log warning.
121-
Complexity: S
122-
123-
- [ ] P0 — **NuGet supply chain hardening**
124-
Why: No lock file, no audit, no package source mapping. Dependency confusion and typosquatting attacks possible.
125-
Evidence: .NET supply chain security best practices; NuGet audit (NU1901-NU1904 warnings).
126-
Touches: All `.csproj` files (add `RestorePackagesWithLockFile`), `NuGet.Config` (add `packageSourceMapping`), `.github/workflows/build.yml` (add `--locked-mode`)
127-
Acceptance: `packages.lock.json` committed. CI build uses `--locked-mode`. `NuGetAudit` enabled at `moderate` level. Package sources mapped explicitly.
128-
Complexity: S
129-
130-
### P1 — Accuracy + platform currency
131-
132-
- [ ] P1 — **Expand leftover signature database to 200+ profiles**
133-
Why: Current 50 profiles cover common apps but benchmark accuracy requires broader coverage. Target: ≥85% accuracy (≤61 leftovers out of 406 artifacts) to reach top-3 in Uninstalr benchmark.
134-
Evidence: Uninstalr 2026 benchmark — HiBit 90%, Total Uninstall 86%; Revo Logs Database covers 12.5k programs. Also fix: duplicate Spotify entry in current DB.
135-
Touches: `Core/Data/leftover-signatures.json`, `Core/Data/LeftoverSignatureDb.cs`
136-
Acceptance: 200+ profiles. Matching algorithm enhanced to handle publisher-based grouping (e.g., all Adobe products share Adobe paths). Duplicate Spotify entry removed.
137-
Complexity: M
138-
139-
- [ ] P1 — **Portable app detection**
140-
Why: Only Uninstalr detects portable apps (Notepad++ Portable, Brave Portable). All 8 other tested tools scored 0. Significant unmet demand.
141-
Evidence: Uninstalr 2026 benchmark — portable app detection section; BCU's folder scan concept in Ideas list.
142-
Touches: New `Core/Packages/PortableAppScanner.cs`, `Core/Packages/PackageManagerScanner.cs`
143-
Acceptance: Scan common portable locations (Desktop, Downloads, USB roots, PortableApps.com folder) for executables without matching registry entries. Show as "Portable" source in program list.
144-
Complexity: M
145-
146-
- [ ] P1 — **Target .NET 10 LTS instead of .NET 9 STS**
147-
Why: .NET 9 STS ends Nov 2026 (too soon). .NET 10 is LTS through Nov 2028. CommunityToolkit.Mvvm 8.4.2 partial properties require .NET 9+ SDK but target any runtime. Includes all .NET 9 benefits plus WPF improvements.
148-
Evidence: .NET 10 release notes; .NET 9 STS EOL Nov 2026; breaking changes audit (empty Grid defs, DynamicResource crashes, P/Invoke search path changes).
149-
Touches: All 4 `.csproj` files — TFM `net10.0-windows10.0.17763.0`. Review P/Invoke DLL loading paths for single-file compatibility.
150-
Acceptance: Build succeeds on net10.0, all tests pass. Note: this supersedes the existing ".NET 9" ROADMAP item — implementer should do .NET 10 directly.
151-
Complexity: M
152-
153-
- [ ] P1 — **Migrate toast notifications from deprecated package**
154-
Why: `Microsoft.Toolkit.Uwp.Notifications` 7.1.3 is archived/unmaintained. No security patches. Windows App SDK `AppNotificationManager` is the supported replacement.
155-
Evidence: NuGet package status (archived); Microsoft migration guidance.
156-
Touches: `Core/Diagnostics/ToastNotifier.cs`, `Core/DeepPurge.Core.csproj`
157-
Acceptance: Toast notifications work on Windows 10 1809+ and Windows 11. Remove `Microsoft.Toolkit.Uwp.Notifications` NuGet reference.
158-
Complexity: S
159-
160-
### P2 — Reliability + developer experience
161-
162-
- [ ] P2 — **Add logging to silent catch blocks in RegistryLeftoverScanner**
163-
Why: 16+ `catch { }` blocks with no logging make field debugging impossible. 88 total silent catches across Core.
164-
Evidence: Code review — `Core/Registry/RegistryLeftoverScanner.cs` has the highest density.
165-
Touches: `Core/Registry/RegistryLeftoverScanner.cs`, other Core files with silent catches
166-
Acceptance: All catch blocks in RegistryLeftoverScanner call `Log.Warn()` with the exception message. Other high-density files (FileLeftoverScanner) follow suit.
167-
Complexity: S
168-
169-
- [ ] P2 — **Fix ManagementObject disposal leak**
170-
Why: `SystemRestoreManager.cs` line 48: WMI `ManagementObject` instances in foreach are never disposed. COM object leak.
171-
Evidence: Code review — foreach loop over `ManagementObjectSearcher.Get()` without disposal.
172-
Touches: `Core/Safety/SystemRestoreManager.cs`
173-
Acceptance: ManagementObject instances disposed after use. Verify no WMI handle leaks under repeated calls.
174-
Complexity: S
175-
176-
- [ ] P2 — **"Always keep" protection flag per program**
177-
Why: Users want to protect critical apps from accidental batch uninstall. Table-stakes safety UX.
178-
Evidence: BCU issue #935 (most-requested safety feature); Revo Pro has similar "exclude" feature.
179-
Touches: `Core/Models/InstalledProgram.cs`, `Core/App/DataPaths.cs` (persist list), `App/Views/MainWindow.xaml` (context menu + visual indicator)
180-
Acceptance: Right-click → "Always Keep" marks a program. Marked programs are excluded from batch uninstall and show a lock icon. Persisted in DataPaths.Config.
181-
Complexity: S
182-
183-
- [ ] P2 — **winget COM API migration**
184-
Why: `winget list --output json` is not a supported CLI option. Current fallback to table parsing is fragile. The `Microsoft.Management.Deployment` COM API is the official programmatic interface.
185-
Evidence: microsoft/winget-cli#4965 (feature request still open); winget export uses schema 2.0 JSON.
186-
Touches: `Core/Packages/PackageManagerScanner.cs`
187-
Acceptance: Use `winget export` for JSON package list or COM API for real-time queries. Remove `ParseWingetTable` fallback. Add test with sample JSON output.
188-
Complexity: M
189-
190-
- [ ] P2 — **External leftover signature loading**
191-
Why: Current DB is embedded-resource only — no way for users or community to contribute profiles without recompilation.
192-
Evidence: RESEARCH.md architecture assessment; BleachBit CleanerML community model; Winapp2 repo (969 stars).
193-
Touches: `Core/Data/LeftoverSignatureDb.cs`, `Core/App/DataPaths.cs`
194-
Acceptance: On startup, scan `DataPaths.Cleaners/*.signatures.json` and merge with embedded DB. User-contributed files take precedence over embedded entries for the same app name.
195-
Complexity: S
196-
197-
### P3 — Polish + differentiation
198-
199112
- [ ] P3 — **Expert/safe mode toggle**
200113
Why: BleachBit's expert mode hides dangerous operations from novice users. Reduces support burden and builds trust.
201114
Evidence: BleachBit 6.0 expert mode; FluentCleaner's anti-bloat philosophy.
@@ -225,11 +138,9 @@ Things worth considering but not on a timeline:
225138
programs list, analogous to the existing winget + scoop path
226139
- **OEM bloat scoring** — heuristics (publisher=Dell/HP/Lenovo, install source=OEM)
227140
to recommend batch-uninstall candidates on factory images
228-
- **Portable app detection** — BCU-style folder scan for unregistered apps
229141
- **Tray icon** — background scheduled cleaning with tray notifications
230142
- **Registry ETW tracing** — add `Microsoft.Diagnostics.Tracing.TraceEvent` for
231143
real-time registry change capture alongside USN journal filesystem tracking
232-
- **Android companion** — nope, scope creep, documented here only to flag it
233144

234145
## What we will NOT ship
235146

0 commit comments

Comments
 (0)