Trust Strategy — Overcoming “Mac Cleaner = Scareware”
Status: DECIDED architecture doc. Governs marketing copy AND in-app UI copy. Any copy, screenshot, or UI flow that violates the Banned Patterns list in this doc is a release blocker — treat it the same as a failing test.
Why this doc exists (the risk, stated plainly)
Three facts collide and none of them are solved by writing better Swift:
- MacKeeper poisoned the category. Pre-2019 MacKeeper ran scareware-style full-screen “your Mac may be infected” popups, was the subject of a 2014 class-action suit alleging it fabricated problems to sell upgrades, and leaked account data for millions of users in a 2015 breach. Clario acquired it in 2019 and the product is now considered legitimate by most reviewers, but the brand damage is permanent — “MacKeeper” is still shorthand for “Mac scam” in casual conversation, and old scareware reviews still dominate search results years later (Macworld, Cybernews reviews, 2026). Every “Mac cleaner” inherits that prior.
- Apple’s own position is that macOS doesn’t need one. There’s no single Apple press statement, but the consistent line from Apple Support Community moderators is direct: cleaning/optimizing/speed-up software “is not necessary,” can “slow down your Mac instead of speeding it up,” and senior community members routinely advise against installing any of it (Apple Discussions threads 255255046, 8409499). Apple’s own answer to “how do I free up space” is Storage Settings, not a third-party app. We are building a product Apple’s own support channel tells users to avoid the category of.
- Apple is actively purging cleaner-shaped App Store scams. Apple removed 82,509 apps in 2024 (Utilities the single largest category, 16,000+ apps) and pulled 17,000+ apps in 2024 and nearly 59,000 in 2025 for bait-and-switch, much of it subscription-trap “cleaner” and “optimizer” utilities using fake storage-full warnings to push weekly subscriptions (Apple Newsroom transparency reports; independent teardown by Connor Tumbleson, Jan 2025, documenting two such apps ranked #7 and #14 among free Utilities). Meanwhile fake CleanMyMac installer sites are an active malware vector delivering crypto-stealers (TechRadar, 2025/2026 coverage). Users have every reason to assume any cleaner is either a subscription trap or malware wearing a costume.
- Free OSS rivals set the honesty bar, not the price bar. PureMac (MIT) and Pearcleaner (13k GitHub stars) are free, open source, and cover caches/Xcode/Homebrew/uninstall. A user can read their source. We can’t compete on “you can read the code” — we’ve decided closed source, paid one-time (see P0-01, P0-07). So every ounce of trust has to come from verifiable behavior, not source access. That’s what this doc designs.
Non-negotiable framing for every section below: we cannot say “trust us.” We have to build things a skeptical user, a security journalist, or a Reddit thread can check without our cooperation.
1. Published deletion-rules manifest
The problem it solves: closed-source binary + Full Disk Access is the exact shape of a supply-chain attack. The only way to neutralize that fear without open-sourcing the app is to open-source what it’s allowed to touch.
Format: a single YAML file, rules.yaml, one entry per rule:
- id: xcode-derived-data
version: 1
category: developer-tools
path_pattern: "~/Library/Developer/Xcode/DerivedData/*"
match_type: glob
action: delete
risk: low
reasoning: >
Xcode regenerates DerivedData automatically on next build. Safe to
delete unconditionally.
requires_confirmation: false
added_in: 1.0.0
references:
- "https://developer.apple.com/documentation/xcode"
- id: chrome-cache
version: 1
category: browser-cache
path_pattern: "~/Library/Caches/Google/Chrome/**"
match_type: glob
action: delete
risk: low
reasoning: "Browser cache, regenerated on demand, no user data."
requires_confirmation: false
added_in: 1.0.0
Where it lives: a public GitHub repo, dfacto-ai/mac-cleaner-rules
(separate from the closed-source app repo — this repo has no reason to be
private and its openness is the point). Every release tag corresponds
exactly to the rules bundle shipped in that app version. Full history is
git log-diffable, so “what changed between v1.2 and v1.3” is a normal PR
diff any user or journalist can read without our help.
How a user verifies the shipped binary uses exactly the published rules — this is the load-bearing mechanism, not the manifest’s existence:
- The app embeds the rules bundle as a signed resource and exposes Settings → About → Rules Bundle → “Verify against published rules”, which fetches the tagged file from the public repo over HTTPS and does a byte-for-byte / SHA-256 diff against the bundle actually loaded at runtime, displaying “Match — you are running the published rules for v1.3.0” or a hard failure with a diff if it doesn’t match.
- The app’s About screen shows the exact git commit SHA of the rules bundle it shipped with, and a deep link to that commit in the public repo.
- The rules bundle is signed (see §5) so a MITM’d or tampered local copy fails verification rather than silently passing.
- No rule is ever evaluated dynamically or fetched over the network at scan time — the manifest is static, bundled at build time, and code review of the (closed) engine against the (open) manifest is exactly the kind of thing the third-party audit in §4 is scoped to check.
Implementable contract:
-
rules.yamlschema (id, version, category, path_pattern, match_type, action, risk tier, human-readable reasoning, requires_confirmation, added_in, references) is the single source of truth for every path the engine can touch — no path pattern may exist in code that isn’t in this file. - Public repo
dfacto-ai/mac-cleaner-rules, MIT or CC0 licensed, tagged per app release, PR-reviewable history. - Build pipeline fails if the embedded rules bundle hash doesn’t match the tag’s published hash (prevents accidental drift, not just malicious drift).
- In-app “Verify against published rules” action with pass/fail/diff UI.
- CHANGELOG entry required in the rules repo for any rule add/change/ removal, in plain English, not just diff noise.
2. “Show me exactly what will be deleted and why” before any action
The problem it solves: the entire scareware genre works by hiding the gap between “we found a problem” and “here is the specific evidence.” Close that gap and the scareware pattern becomes structurally impossible to execute, not just against our style guide.
UI contract:
- Every destructive action (delete, empty trash, uninstall) is preceded by a Review screen that is not skippable and not defaulted to “select all.” Nothing is pre-checked beyond items previously explicitly confirmed by the user in an earlier session for the identical, unchanged path.
- The Review screen is a flat, sortable, searchable list. Each row shows:
path (real path, not a category euphemism), size, rule id
that matched it (linking to that exact rule in the published manifest —
§1), one-sentence reasoning taken verbatim from the manifest’s
reasoningfield (no separate marketing-written copy that could drift from the real reason), last-modified / last-accessed date, and a per-row checkbox. - Any item whose manifest
risktier is abovelowis unchecked by default and requires an explicit per-item tap to include, plus shows an inline one-line risk note (e.g., “Xcode may re-download this — a few minutes’ rebuild, no permanent loss”). - Grand total is shown as exact bytes and item count, never rounded up or displayed as a leading marketing number (“12.4 GB across 1,204 items,” not “Reclaim up to 40 GB!”).
- The confirm button reads what it does: “Delete 1,204 items (12.4 GB)” — never “Clean Now,” “Optimize,” or “Boost.”
- After the action, a result receipt lists exactly what was deleted (same path-level detail), with a single “Undo” affordance (§7) and is saved to a local, user-visible log the user can export or delete.
- Scanning itself never deletes or modifies anything — read-only until the user explicitly confirms on the Review screen. No “auto-clean” default mode ships in v1.
Implementable contract:
- Review screen is architecturally mandatory: the delete code path has no entry point that doesn’t originate from a confirmed Review-screen selection (enforced in code, not just UI convention — the audit in §4 checks this).
- Every row’s reasoning string is sourced from
rules.yaml, not a separate copy deck — one string, two places it’s read from. -
risk: mediumorrisk: highrows default unchecked;lowmay default checked only after the user has confirmed that specific rule once before (tracked per rule id, resettable in Settings). - No numeric total is ever shown pre-scan or as an estimate before the actual list is computed.
3. Zero telemetry by default, plus a viewer for opt-in telemetry
The problem it solves: a closed-source app that phones home is indistinguishable, from the user’s vantage point, from spyware. The fix isn’t a privacy-policy paragraph, it’s making “phones home” checkable.
Implementable contract:
- No network calls of any kind on first launch, during scan, or during delete, except the explicit, user-initiated “Verify against published rules” fetch (§1) and app-update checks (which are themselves an opt-out Sparkle-style pull, not push, and logged the same way).
- Crash reporting, analytics, and any usage telemetry are off by default, opt-in only, asked once, never nagged for.
- If a user opts in, Settings → Privacy → Telemetry → “What we send” renders the literal JSON payload of the next event that would be sent, live, before it’s sent — not a description of it, the actual bytes. A running local log (view + export + clear) of every telemetry event actually sent is kept for the life of the opt-in.
- Telemetry payloads are schema-frozen and published in the same public
rules repo (
telemetry-schema.yaml) — field names, types, and an explicit “never includes: file paths, filenames, file contents, usernames” statement, so the schema itself is auditable independent of any single payload. - A network-level claim (“this app makes zero outbound connections with
telemetry off”) must be a testable claim: ship a documented way to
verify it (e.g., a note that Little Snitch / Lulu /
nettopwill show no connections during a scan-and-delete cycle with telemetry off), and this is one of the things the third-party audit in §4 explicitly tests and signs off on.
4. Third-party security audit, published in full (owned by P4-07)
This section specifies what P4-07’s gate must cover; P4-07 executes it.
Scope the audit must cover:
- Every trust boundary identified in the P2-06 threat model, re-verified against shipped code, not the design doc.
- Privileged-helper / XPC request validation and client authentication (anything running as root or with elevated entitlements).
- TOCTOU windows between “scan found this path” and “delete acted on this path” (symlink swaps, path re-use races).
- Rules-bundle signature verification (§1) — can a tampered or unsigned bundle be loaded?
- Full Disk Access usage: does the app read/exfiltrate anything outside what the rules manifest declares?
- Network behavior end-to-end: confirms the zero-telemetry-by-default claim in §3 by observation, not by reading our code.
- Deletion path: confirms nothing is deletable outside the manifest-matched set (i.e., §1’s “no path in code that isn’t in the manifest” claim, audited from the binary side).
- Update mechanism (Sparkle or equivalent) integrity — signature checks, downgrade protection, MITM resistance.
Firms that do this kind of macOS/desktop-app audit (all have public track records auditing comparable trust-sensitive macOS apps, per current search): Cure53 (Berlin — audited ExpressVPN macOS, Obscura VPN macOS app + network extension, NordVPN desktop apps, Bitwarden desktop, Obsidian); Trail of Bits (New York — Obsidian Sync infra/crypto, broad macOS/ desktop and crypto audit practice). Both routinely publish full reports (not just summaries) for privacy/security-focused consumer apps, which is the standard we’re committing to.
Implementable contract (for P4-07 to execute):
- Engage a firm from the above list (or equivalent-caliber alternative) before v1.0 general release.
- Full report published in the public rules repo or a dedicated
security/doc — not a summary, not a badge, the actual report, redacted only for anything that would itself create a vulnerability (rare, and the redaction itself disclosed). - Any finding rated medium or above is a release blocker until fixed and re-verified.
- Repeat audit cadence: at minimum on any major version that touches the helper/XPC boundary or the deletion engine.
5. Reproducible builds + published checksums
Honest assessment of feasibility: full bit-for-bit reproducible builds for a notarized Swift/SwiftUI app are not fully achievable today and we should say so rather than claim it. The blockers are real and external to us: Xcode ships its own clang/swiftc per version and optimization output can vary release to release; Apple’s notarization step (stapling a ticket into the binary) is itself a non-deterministic, Apple-side transformation — two notarization runs of the identical input produce different stapled output because the ticket embeds Apple-side metadata. SwiftPM dependency resolution has historically had its own reproducibility gaps. The one public reference case researching this for a security-sensitive Swift/iOS app (Immuni, the Italian COVID-tracing app) concluded it’s “feasible but not fully achieved” even with dedicated effort — that’s the honest ceiling for a team our size.
Best available substitute, and what we commit to instead:
- Pin and publish the exact toolchain: Xcode version, Swift version,
macOS build-host version, and full
Package.resolvedare published per release tag in the app repo (not just the rules repo). - Publish checksums for every shipped artifact: SHA-256 of the
.dmg/.pkgand of the unstapled.appbundle prior to notarization, published in the release notes and signed with a published PGP/minisign key so the checksum list itself can’t be silently edited after the fact. - Independently reproducible pre-notarization build: commit to building
from a clean checkout with the pinned toolchain producing a
deterministically-hashable
.appbefore the Apple notarization step — this is the part actually under our control, and where we can make a real “you can verify this yourself” claim, with the caveat stated plainly that the final notarized artifact will differ byte-for-byte from a third-party rebuild because of Apple’s non-deterministic stapling, even though the underlying app is identical. - Say this explicitly in the trust docs, rather than claiming full reproducibility we can’t deliver: “We publish exact toolchain versions and checksums, and the app build itself is reproducible from source given the pinned toolchain; the final notarized wrapper differs byte-for-byte between any two notarization runs because that step is controlled by Apple, not us — this is a known limitation of all notarized macOS apps, not something specific to ours.”
Implementable contract:
-
.xcode-version, Swift version, andPackage.resolvedpublished per tagged release. - SHA-256 (+ signature) of shipped
.dmg/.pkgand of the pre-notarize.apppublished in release notes. - CI documents the exact build command used for the official release so a third party can attempt the pre-notarize reproduction themselves.
- Public statement of the notarization-step limitation (above) lives in the same doc as the checksums — no claiming more than is true.
6. No scareware patterns, ever — Banned Patterns list
Phrased so an auditor (or CI string-scan) can mechanically check app strings, screenshots, App Store copy, and marketing copy against it. Any occurrence of any pattern below, anywhere in shipped copy, is a release blocker.
- No unearned urgency language. Banned strings/patterns: “at risk,” “your Mac is at risk,” “warning,” “danger,” “critical issue found,” “act now,” “immediately,” used to describe a normal, harmless condition (cache size, log file count, etc.). Exception: genuine, factual risk statements written in the Review screen’s per-item reasoning (§2), which must be specific and sourced from the manifest, not generic alarm copy.
- No countdown timers or artificial deadlines anywhere in the app or its marketing — no “offer expires in,” no scan-result countdown, no “your discount ends in.”
- No inflated or estimated “GB found” numbers. Every number shown to the user is the exact, already-computed size of an already-identified set of items (§2) — never a pre-scan teaser number, never a rounded-up marketing figure (“reclaim up to 40GB”), never a number that includes items not individually listed on the Review screen.
- No “scanning you into a purchase.” The free scan must show real, itemized results with real paths and real sizes — never a paywall that blocks seeing what was found, only a paywall (if any) on the delete action. Never a scan result that’s deliberately vague (“47 issues found!”) to force a purchase to see detail.
- No fake system-state indicators. No red/yellow/green “health score,” “Mac Score,” or gauge widget not backed by a specific, inspectable, individually-listed metric. No badge/counter implying malware, viruses, or infections — macOS on Apple Silicon doesn’t have the “virus problem” this implies, and claiming otherwise is exactly the deception category Apple’s fraud team is actively removing apps for.
- No dark-pattern consent flows. No pre-checked “select all” on destructive actions. No disabled/greyed-out “Skip” or “No thanks” buttons. No consent dialogs where declining is visually smaller/lower- contrast than accepting.
- No auto-clean / silent background deletion in any default configuration — deletion always requires the explicit Review-screen confirmation in §2, full stop, no “smart mode” that skips it.
- No comparison-shaming imagery: no “before/after” red-to-green Mac icons, no “your Mac is dirty” illustrations, no anthropomorphized “sick Mac” mascots.
- No subscription dark patterns: no auto-enrolling a trial into a paid subscription without a clear, dated, in-app reminder (moot for us — we’re paid one-time, but this stays banned permanently in case pricing ever changes, per P0-07 decisions).
- No claims macOS itself contradicts. Never claim to “speed up,” “optimize,” “boost,” or “supercharge” the Mac via cache-clearing — Apple’s own guidance is that this doesn’t work and can make things worse; our claims are limited to disk-space-recovery facts we can prove per-item, matching the Honesty Contract (P0-06).
Mechanical check: CI includes a string-scan over all .strings/
.stringsdict resources and marketing copy in the public repo for the
banned tokens above (risk, danger, warning, at risk, act now, immediately,
optimize, boost, speed up, clean now, up to \d+\s?GB, expires in, health
score) with an explicit allowlist file for the rare legitimate use (e.g. a
genuine “at risk” only inside an itemized, manifest-sourced reasoning
string) reviewed manually per exception.
7. Full undo for everything
Implementable contract:
- Every delete operation moves items to a dedicated app-managed holding area (not just system Trash, which users empty and which other cleaners also target) with a default 30-day retention before permanent removal, user-configurable in Settings.
- The post-delete result receipt (§2) carries a persistent, one-tap “Undo this batch” action, scoped to the exact batch, that restores every item to its original path with original metadata (mtime, permissions) intact.
- Undo is available from a persistent History screen (not just the immediate post-action toast) listing every past deletion batch by date, item count, and size, each independently undoable, for the retention window.
- The one and only category exempted from holding-area undo is content
that is provably regenerable and explicitly marked
requires_confirmation: false, risk: lowin the manifest (e.g. browser cache) — and even there, the Review screen (§2) still shows exactly what’s being deleted before it happens; “regenerable” is a convenience for holding-area storage cost, not a reason to skip disclosure. - Holding-area storage itself counts toward, and is visible in, the app’s own disk usage — no claiming space “reclaimed” that’s actually sitting in our own holding area.
Three additional trust mechanisms (not in the original list)
- A public, dated “incidents” page — even before we have any
incidents. Ship
dfacto-ai/mac-cleaner(or the rules repo) with aTRUST-LOG.mdthat we commit to updating within 48 hours of any confirmed data-loss report, false-positive deletion pattern, or security finding, with root cause and fix. An empty, dated, publicly-watched log from day one is more credible than a promise to be transparent someday — and it directly answers the MacKeeper-style fear (“what happens when they screw up”) before it happens. - A local, tamper-evident action log the user owns, not us. Every
scan and delete writes to a local SQLite/JSON log the user can open,
export, or
grepdirectly from Terminal, independent of the in-app History UI (§7) — so “what did this app do to my Mac” is answerable without trusting our UI to render it honestly, only trusting the raw log file, which we document the format of. - A standing “report a false positive” loop that visibly changes the
published manifest. A one-tap in-app “this shouldn’t have been
flagged” action per Review-screen item files a public issue against the
mac-cleaner-rulesrepo (§1) pre-filled with the rule id and path pattern (no personal data), and we commit to a stated SLA (e.g. 5 business days) to respond in that public issue. This turns “the rules are published” (a static claim) into “the rules visibly respond to users” (a living one), which is the difference between a compliance document and an actual trust signal.
What we say when a user asks “why should I trust a closed-source cleaner?”
We’re closed source because that’s the trade-off of a sustainable, one-time-paid product — but “closed source” doesn’t have to mean “opaque.” Every path we’re capable of touching is published, versioned, and diffable at github.com/dfacto-ai/mac-cleaner-rules; the app can verify its own shipped rules against that public list in one tap. Before anything is deleted, you see the exact files, sizes, and the exact reason, sourced from that same public list — not a summary, not a “1,204 issues found” teaser. Nothing is sent off your Mac unless you explicitly turn telemetry on, and if you do, you can watch the exact payload before it’s sent. A named independent security firm audits the app before release and we publish the full report, not a badge. And if we ever get something wrong, every deletion is undoable for 30 days, and we log it in public. You’re not trusting our promises — you’re trusting things you or a journalist can check without needing our source code at all.