fix: PATH hijacking, orphan process kill, log privacy sanitization (SEC-007, SEC-008, PRIV-001)#376
Conversation
…EC-007, SEC-008, PRIV-001)
📝 WalkthroughWalkthroughThis PR hardens security and stability across two Windows service executables. UninstallerService prevents PATH hijacking by resolving trusted uninstall binaries to absolute System32 paths. SpeedTestService prevents orphaned Ookla processes during cancellation and removes sensitive paths from debug logs. Changes are documented in the 0.48.13 release notes. ChangesSecurity and Stability Hardening
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~22 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
|
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@SysManager/SysManager/Services/SpeedTestService.cs`:
- Around line 208-220: The Process stdout/stderr reads
(proc.StandardOutput.ReadToEndAsync(linked) and
proc.StandardError.ReadToEndAsync(linked)) can throw OperationCanceledException
before the existing WaitForExitAsync catch runs, so move the two ReadToEndAsync
calls inside the same try/catch that surrounds WaitForExitAsync (or create a
single try that calls both ReadToEndAsync and then WaitForExitAsync) and in the
catch for OperationCanceledException ensure you call
proc.Kill(entireProcessTree: true) if !proc.HasExited (handling
InvalidOperationException as currently done) before rethrowing; this guarantees
proc cleanup even when cancellation happens during stream reads.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 4b459ac9-3568-4ebc-bbff-9cfdce87bcbe
📒 Files selected for processing (3)
CHANGELOG.mdSysManager/SysManager/Services/SpeedTestService.csSysManager/SysManager/Services/UninstallerService.cs
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: Build & unit tests
- GitHub Check: Analyze (csharp)
🔇 Additional comments (3)
CHANGELOG.md (1)
9-19: LGTM!SysManager/SysManager/Services/UninstallerService.cs (1)
258-284: LGTM!SysManager/SysManager/Services/SpeedTestService.cs (1)
228-229: LGTM!Also applies to: 289-290, 357-358, 368-369
| var stdout = await proc.StandardOutput.ReadToEndAsync(linked); | ||
| var stderr = await proc.StandardError.ReadToEndAsync(linked); | ||
| await proc.WaitForExitAsync(linked); | ||
| try | ||
| { | ||
| await proc.WaitForExitAsync(linked); | ||
| } | ||
| catch (OperationCanceledException) | ||
| { | ||
| // Timeout or user cancellation — kill the orphan process | ||
| try { if (!proc.HasExited) proc.Kill(entireProcessTree: true); } | ||
| catch (InvalidOperationException) { /* already exited */ } | ||
| throw; | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
file="$(fd -t f SpeedTestService.cs | head -n1)"
echo "Inspecting cancellation scope in: $file"
nl -ba "$file" | sed -n '200,222p'Repository: laurentiu021/SystemManager
Length of output: 216
🏁 Script executed:
cat -n SysManager/SysManager/Services/SpeedTestService.cs | sed -n '200,230p'Repository: laurentiu021/SystemManager
Length of output: 1738
🏁 Script executed:
# Search for other Process + StandardOutput/StandardError patterns
rg -n "StandardOutput\.ReadToEndAsync|StandardError\.ReadToEndAsync" SysManager --type cs -B 5 -A 5Repository: laurentiu021/SystemManager
Length of output: 2373
🏁 Script executed:
# Check for other Process with cancellation token patterns
rg -n "WaitForExitAsync.*CancellationToken|ReadToEndAsync.*CancellationToken" SysManager --type cs -B 3 -A 3Repository: laurentiu021/SystemManager
Length of output: 52
Protect process cleanup against cancellation during stream reads.
ReadToEndAsync(linked) on lines 208-209 can throw OperationCanceledException before reaching the try/catch block, bypassing the proc.Kill() cleanup and leaving an orphaned process. Both reads must be wrapped in the cancellation-guarded block.
Suggested fix
using var proc = new Process();
proc.StartInfo = psi;
await Task.Run(() => proc.Start(), linked).ConfigureAwait(false);
- var stdout = await proc.StandardOutput.ReadToEndAsync(linked);
- var stderr = await proc.StandardError.ReadToEndAsync(linked);
+ string stdout;
+ string stderr;
try
{
+ var stdoutTask = proc.StandardOutput.ReadToEndAsync(linked);
+ var stderrTask = proc.StandardError.ReadToEndAsync(linked);
await proc.WaitForExitAsync(linked);
+ stdout = await stdoutTask.ConfigureAwait(false);
+ stderr = await stderrTask.ConfigureAwait(false);
}
catch (OperationCanceledException)
{
// Timeout or user cancellation — kill the orphan process
try { if (!proc.HasExited) proc.Kill(entireProcessTree: true); }
catch (InvalidOperationException) { /* already exited */ }
throw;
}🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@SysManager/SysManager/Services/SpeedTestService.cs` around lines 208 - 220,
The Process stdout/stderr reads (proc.StandardOutput.ReadToEndAsync(linked) and
proc.StandardError.ReadToEndAsync(linked)) can throw OperationCanceledException
before the existing WaitForExitAsync catch runs, so move the two ReadToEndAsync
calls inside the same try/catch that surrounds WaitForExitAsync (or create a
single try that calls both ReadToEndAsync and then WaitForExitAsync) and in the
catch for OperationCanceledException ensure you call
proc.Kill(entireProcessTree: true) if !proc.HasExited (handling
InvalidOperationException as currently done) before rethrowing; this guarantees
proc cleanup even when cancellation happens during stream reads.
| var systemDir = Environment.GetFolderPath(Environment.SpecialFolder.System); | ||
| var resolvedName = exeFileName.EndsWith(".exe", StringComparison.OrdinalIgnoreCase) | ||
| ? exeFileName : exeFileName + ".exe"; | ||
| exe = System.IO.Path.Combine(systemDir, resolvedName); |
…EC-007, SEC-008, PRIV-001) (#376) Co-authored-by: laurentiu021 <laurentiu021@users.noreply.github.com>
Summary
PRIORITY 1 security/reliability fixes from QA audit.
Changes
SEC-007: PATH hijacking prevention (CRITICAL)
SEC-008: Orphan process kill (CRITICAL)
PRIV-001: Log privacy sanitization (MEDIUM)
Build
Summary by CodeRabbit
Release Notes v0.48.13
Bug Fixes