This repository is a local-only macOS SwiftUI menu bar app with a WidgetKit extension. I did not find any obvious remote-code-execution, secret-exfiltration, or network-exposure issues, largely because the app has no network stack and accepts very little untrusted input.
The main security risks are local trust-boundary issues:
- The app launches an external cleanup tool by absolute path without validating the target bundle identity.
- The main app is intentionally unsandboxed while also exposing process-management and app-launch capabilities.
- The "Release Memory" path can send
SIGKILLto an entire process group based on broad executable-path matching. - The custom URL scheme accepts any
perfmonitor://invocation and immediately activates the UI.
Method note: the requested security-best-practices skill does not ship Swift/macOS-specific reference docs, so this review uses manual Swift/macOS security analysis instead of framework-specific checklist files.
SEC-001mitigated in the current working tree by validating the expectedDiskCleanupTool.appbundle identifier before launch and showing a feature-unavailable alert when the app is absent or untrusted.SEC-003mitigated in the current working tree by tightening Claude path matching and limitingSIGKILLto Claude-identified processes only.SEC-004mitigated in the current working tree by accepting only the exact widget deep link shape (perfmonitor://show).SEC-002remains open. Fully addressing it requires architectural work because the current app design intentionally depends on unsandboxed capabilities for process inspection and termination.
No critical findings.
No high-severity findings.
Impact: clicking CLEAN UP DISK can launch arbitrary local code under the current user account if /Applications/DiskCleanupTool.app is replaced with an unexpected bundle.
- Code: PerformanceMonitor/Views/StatsOverviewView.swift:116
- Relevant lines:
let url = URL(fileURLWithPath: "/Applications/DiskCleanupTool.app")NSWorkspace.shared.openApplication(at: url, configuration: NSWorkspace.OpenConfiguration())
- Why it matters:
- This trusts path presence alone.
- There is no verification of bundle identifier, team identifier, code signature, or expected executable.
- For a local utility launcher, path-only trust is a weak control.
- Recommended fix:
- Verify the bundle identifier before launch.
- Prefer verifying the code signature / designated requirement if this is intended to launch a specific trusted helper app.
- Fail closed with a user-visible error when the installed app does not match expectations.
Impact: if the app, a future dependency, or a future input surface is compromised, it runs with full user-level local access instead of container-scoped access.
- Code: project.yml:35
- Code: PerformanceMonitor/PerformanceMonitor.entitlements:5
- Relevant lines:
ENABLE_APP_SANDBOX: false<key>com.apple.security.app-sandbox</key><false/>
- Why it matters:
- The app enumerates processes, terminates apps, force-kills process groups, reads filesystem stats, and launches external apps.
- In a non-sandboxed app, any future bug in URL handling, parsing, plug-in loading, or helper execution has a much wider blast radius.
- Recommended fix:
- If these capabilities are required, document the trust model explicitly and keep the unsandboxed surface as small as possible.
- Consider moving privileged/destructive operations behind a narrower helper boundary rather than keeping the whole UI app unsandboxed.
- Avoid adding new input surfaces to the unsandboxed target unless strictly necessary.
Impact: a local binary placed under a matching Claude-like path can be swept into the SIGKILL path, causing unintended local denial of service when the user clicks RELEASE MEMORY.
- Code: PerformanceMonitor/Services/ProcessManager.swift:44
- Code: PerformanceMonitor/Services/ProcessManager.swift:211
- Code: PerformanceMonitor/Services/ProcessManager.swift:230
- Code: PerformanceMonitor/Services/MemoryPurgeService.swift:10
- Code: PerformanceMonitor/Views/StatsOverviewView.swift:121
- Why it matters:
- Process identity is inferred from
path.contains(".local/share/claude/") || path.hasSuffix("/MacOS/Claude"). - Once a process group crosses the threshold, every PID in that group receives
SIGKILL. - There is no extra verification step, no allowlist of signed binaries, and no confirmation dialog before destructive action.
- Process identity is inferred from
- Recommended fix:
- Tighten process identification beyond path substrings.
- Verify expected executable names / bundle identifiers / parent process lineage before kill.
- Consider a confirmation step when the action will kill multiple processes.
Impact: any local app can trigger nuisance popover activation or repeated foregrounding of the app.
- Code: PerformanceMonitor/Info.plist:19
- Code: PerformanceMonitor/App/PerformanceMonitorApp.swift:56
- Why it matters:
- The handler only checks
url.scheme == "perfmonitor". - Host, path, and caller identity are not validated.
- This is low severity today because the action only shows the popover, but it is still an externally triggerable local action.
- The handler only checks
- Recommended fix:
- Validate the exact URL shape you expect, for example
perfmonitor://show. - Ignore unknown hosts and paths.
- Keep the handler side-effect-free beyond the minimal UI action.
- Validate the exact URL shape you expect, for example
- I found no network clients, remote API calls, embedded web views, or server-facing endpoints in the repository.
- I found no obvious secret storage, token handling, or credential persistence.
- The widget shared store writes only basic system stats rather than sensitive user data.
- The widget target remains sandboxed even though the main app does not.
- Fix
SEC-001first by validating the cleanup tool before launch. - Decide whether the unsandboxed main app is an intentional permanent requirement; if yes, document the trust model.
- Harden
SEC-003before adding any more destructive process-management features. - Tighten the URL handler to only accept the exact widget deep link shape.