Skip to content

privacykey/privacycommand

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

74 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

privacycommand

privacycommand

drop an app. see everything it touches.

Forensic permission audits for any macOS app — built for security teams, IT, and privacy-conscious users.

Latest release Downloads Homebrew macOS 13+ License: MIT

Download · Release notes · Report an issue


Warning

This is a beta — pre v1.0. privacycommand is under active development. Expect occasional crashes, behaviour changes between releases, and a report format that may still shift. If you see any bugs, please attach the matching .ips from ~/Library/Logs/DiagnosticReports/ to a new issue or report a security vulnerability through github or the security email.

What it does

Drop a .app bundle (or a .dmg) onto privacycommand and it produces a full forensic report of what the app actually touches:

  • Static analysis — entitlements, code-signing (the 10-character signing Team ID expanded to the developer's name), notarization deep-dive (stapler / spctl / SHA-256), URL schemes, document types, hard-coded domains and URLs, embedded launch agents and helpers, third-party SDK fingerprints (LaunchDarkly, Firebase, Mixpanel, AdMob, …), feature flags and trial-state strings, secrets and license-key names, anti-analysis signals, dylib hijacking surface, and Apple's Privacy Manifest cross-checked against what the binary actually uses.
  • Forensic binary summary — a plain-English read of what the main binary links and calls, including an outbound network call-sites map: which functions can open a connection, the networking symbols they reach for (BSD sockets, getaddrinfo, CFNetwork, Network.framework nw_*), and any host or URL literals sitting next to them. Any call site can be decompiled on demand (if you have Ghidra installed), and for relaunchable, non-hardened-runtime apps you can capture a live call stack that ties an actual outbound connection back to the function that opened it.
  • App Store privacy labels — when the bundle was installed from the Mac App Store, privacycommand fetches the developer's declared Privacy Nutrition Labels from apps.apple.com and shows them next to its static-analysis findings, so you can see whether the developer's claims line up with what the binary contains.
  • Telemetry callout — a Dashboard card flags how many analytics, advertising, and attribution SDKs the bundle ships, with a heat-graded count and per-category breakdown.
  • Background Task Management — every login item, launch agent, daemon, and helper the app has registered, fetched via the privileged helper so there's no admin prompt.
  • Feature flags & trials — the names of isPro, isTrial, subscription_status, experiment_id, and platform-specific switches (LaunchDarkly, Optimizely, Firebase Remote Config, PostHog, Statsig, Unleash) that the binary checks at runtime.
  • Monitored runs — launch the inspected app under privacycommand and watch its file events (via an optional privileged helper running fs_usage), network destinations (reverse-DNS-labelled, with click-through IP lookups, row highlighting, and a highlighted-only filter), child processes, pasteboard / camera / microphone / screen-recording activity, USB device interactions, and resource usage in real time.
  • Network kill switch — block the inspected app's outbound traffic system-wide via a pf anchor installed by the helper. Watch how the app handles being cut off.
  • VM mode — a guest agent that runs inside a macOS VM (VirtualBuddy / UTM / Parallels) and ships observations back to the host across the VM boundary, for analysing apps you'd rather not run on your bare-metal machine.
  • Compare runs — diff any two saved reports side by side from the History tab. Added and removed entitlements, domains, SDKs, login items, and findings are colour-cued, with a "show only changes" toggle — so you can see exactly what an app update introduced.
  • Batch scan — point privacycommand at a folder (or all of /Applications) and triage many apps at once in a sortable, filterable table: risk tier, warning/error counts, and headline signals per app. The same analyzer runs on each; one click opens any app in the main window for the full deep-dive.
  • Reports — every finding exports as JSON, HTML, or PDF.

Install

Homebrew (recommended)

brew install privacykey/tap/privacycommand

That's it. The tap lives at privacykey/homebrew-tap; brew upgrade --cask privacycommand keeps it current. When privacycommand detects it's running from a Homebrew Caskroom, it disables in-app updates so brew stays in charge of the on-disk version.

Direct download

Grab the signed + notarized .dmg from the latest release and drag the app to /Applications. In-app updates are handled by Sparkle 2; they're off by default — you opt in via Settings → Updates.

Build from source

git clone https://github.com/privacykey/privacycommand.git
cd privacycommand/privacycommand
open privacycommand.xcodeproj

Then in Xcode:

  1. File → Add Package Dependencies…https://github.com/sparkle-project/Sparkle (Up to Next Major from 2.9.0). Tick the Sparkle product on the privacycommand target.
  2. Select the privacycommandHelper target → Signing & Capabilities → set Team to match the app.
  3. ⌘B.

The Swift Package Manager target builds with swift build from privacycommand/; tests run with swift test.

Command line

The repo also builds auditctl, a small CLI over the same analyzer — handy for scripting and CI. Build it once with swift build -c release from privacycommand/, then:

# Full static report for a single app (pretty-printed; non-zero exit on parse failure)
swift run -c release auditctl /Applications/SomeApp.app

# Privacy-preview apps *before* you update them. With no arguments, preview
# checks your outdated Homebrew casks; --all-apps scans everything installed.
swift run -c release auditctl preview
swift run -c release auditctl preview --all-apps --only-noteworthy --min-tier warn
swift run -c release auditctl preview --json

# --fetch downloads each incoming cask build and diffs it against the version
# you have installed, so you can see what an update *adds* before you take it.
swift run -c release auditctl preview --fetch firefox

preview is inform-only: it never runs brew, never blocks an update, and always exits 0. It reuses the same static analyzer and risk scoring as the app, and understands .dmg and .zip cask artifacts (.pkg is skipped). Heads-up: with --fetch, an incoming build is analyzed before Gatekeeper has cleared it, so a one-off "notarization" difference can just be a fresh-download artifact (the output flags this).

Screenshots

Screenshots go here once the brand site is up. The Dashboard renders telemetry, App Store privacy labels, live probes, and a forensic findings list; the Static tab walks every signal we extract from the binary.

CleanShot 2026-04-29 at 19 09 22

How it works

privacycommand is a SwiftUI app backed by a pure-Swift analyzer library and an optional privileged helper. The architecture is split deliberately:

Layer Path Notes
Analyzer logic privacycommand/Sources/privacycommandCore/ Headless, AppKit-free; runs from CLI, tests, GUI
App UI privacycommand/Sources/privacycommand/ SwiftUI views + view-models
Privileged helper privacycommand/Sources/privacycommandHelper/ XPC service installed via SMAppService.daemon
Guest agent (VM) privacycommand/Sources/privacycommandGuestAgent/ Runs in-VM, ships observations to the host

Read architecture.md for the longer version.

Updates

Updates ship through two channels that share the same DMG:

  1. Direct downloads receive in-app updates via Sparkle 2. Auto-checks are off by default — opt in via Settings → Updates.
  2. Homebrew users update via brew upgrade --cask privacycommand. privacycommand detects Cask installs and disables Sparkle's installer to stay out of brew's way.

The appcast feed is hosted on gh-pages at https://privacykey.github.io/privacycommand/appcast.xml and signed with EdDSA — see docs/RELEASES.md for the release flow.

Privacy & telemetry posture

privacycommand is a privacy tool and behaves like one:

  • No analytics. privacycommand does not ship any analytics SDKs. There is no telemetry endpoint, no install counter, no crash-report bucket.
  • Network calls are explicit and bounded.
    • DNS reverse lookups for destinations the inspected app contacts (so the Network tab can label 8.8.8.8 as dns.google).
    • Mac App Store privacy-label lookups against itunes.apple.com and apps.apple.com — keyed by the inspected app's bundle ID, never your data.
    • Sparkle appcast fetch from privacykey.github.io when you check for updates.
  • All analysis runs locally. The inspected app's contents never leave your machine.
  • The helper is opt-in. Without the helper, privacycommand still works — file-event monitoring is unavailable and the Background Task Management audit asks before triggering an admin prompt.

Contributing

Issues and PRs welcome. Before opening a PR:

  • Run swift test from privacycommand/ and confirm it passes.
  • For UI changes, attach a before/after screenshot.
  • For new analysis signals, add a Knowledge Base entry alongside the detector — privacycommand explains what every finding means in plain English, and we want to keep that contract.

Security disclosures

If you find a security issue, please don't open a public issue. Email security@privacykey.org with the details. We aim to respond within 72 hours.

Related products

privacycommand is a privacykey project

License

Released under the MIT License.

About

Static and basic dynamic forensics on MacOS apps. See if bundled with telemetry, permissions requested and preview updates before they land

Topics

Resources

License

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors