1 If you think you're hit right now
The first hours: assume compromise, move from a clean device.
If a process may have run as you, treat everything that account touched as already stolen — keys, tokens, passwords, cookies, SSH keys. Work the steps in order. Don't start by "cleaning" the suspect machine; start by securing what it could reach.
-
Do this first
Rotate credentials from a different, clean device
Use your phone or another known-good computer — not the suspect Mac. Anything you type into a compromised machine can be captured again. Rotate, and turn on phishing-resistant 2FA wherever it's offered.
- Your Mac login password, and your password-manager master password (then review its account activity log for unfamiliar sign-ins).
- API keys and developer tokens: cloud providers, GitHub (regenerate SSH keys + fine-grained tokens), CI, package registries, AI/LLM keys.
- Apple ID and Google: set a recovery key, review trusted devices, drop SMS as a recovery factor.
- Financial / payment accounts, and anything with money attached.
- Log out of all browser sessions everywhere, then sign back in — stored cookies were stealable, so a password change alone isn't enough.
-
Preserve evidence before you remove anything
If you might want to understand what happened — or report it — copy the suspicious artifacts to an external drive first. Deleting them destroys the only record of how it got in and what it did.
# List everything set to auto-start (this is where persistence lives) sudo launchctl list ls -la /Library/LaunchDaemons /Library/LaunchAgents ~/Library/LaunchAgents # Common hiding spot: payloads masquerading as Apple services in hidden dirs ls -la ~/Library/Application\ Support/.com.apple.* 2>/dev/null # Copy anything suspicious to an external drive before touching it mkdir -p /Volumes/EVIDENCE/mac-incident sudo cp -p /Library/LaunchDaemons/<suspect>.plist /Volumes/EVIDENCE/mac-incident/A free, signed scanner is the fastest way to see auto-start items you'd otherwise miss — run KnockKnock (Objective-See) and export the results. -
Audit persistence — and don't trust a "clean" antivirus result
Modern stealers disguise themselves as system processes and drop a root LaunchDaemon that relaunches a hidden payload as your user, often on a tight loop. Antivirus can remove the active binary while leaving the root scaffolding loaded — a green dashboard is not proof the machine is clean.
- Look for launchd labels that mimic Apple naming (e.g.
com.apple.*,com.<vendor>.helper) but point at hidden dotfiles or scripts in your home folder. - Check for watchdog loops: a daemon whose job is to relaunch another process every few seconds.
- Check for captured-secret files — short hidden files written near the payload.
If you do choose to neutralize a live item before wiping (it stops the bleeding; it does not make the machine trustworthy):
sudo launchctl bootout system/<bad-label> sudo rm -f /Library/LaunchDaemons/<bad-label>.plist launchctl print system/<bad-label> # expect: Could not find service - Look for launchd labels that mimic Apple naming (e.g.
-
Decide: clean in place, or wipe
For a single benign-looking item caught instantly, careful removal may be enough. But a machine that carried root persistence for any length of time, or where a cleanup looks partial or inconsistent, can't be trusted in place. When in doubt, wipe. A rebuild is hours; trusting a still-dirty machine with your credentials is the more expensive mistake.
The honest framing: the malware is the event, the rebuild is the fix. Removing what you can see doesn't tell you what you can't.
2 Rebuild clean
Erase, reinstall, and set the accounts up so one prompt isn't game over.
Your work should already live on a remote (Git host) and a backup — confirm that first, then wipe without fear of losing it. The single biggest change here is to stop running as admin day to day.
-
Confirm your data is safe off the machine, then erase
Verify your code is pushed to its remote and your documents/photos are in a backup you've test-restored. Then: System Settings → General → Transfer or Reset → Erase All Content and Settings. For extra assurance, also reinstall macOS from Recovery (hold the power button → Options).
- Repos pushed to your Git host (that's your clean copy — you'll re-clone, not restore).
- Documents, photos, and media confirmed in a backup, with a test restore that actually worked.
- Apple ID password already changed from a clean device — you'll need it to set the Mac back up.
-
Set up accounts: separate admin, standard daily, time-boxed elevation
On the fresh setup screen, create an admin account you won't use daily (for installs only), then create a standard (non-admin) account and live in it. Running as standard turns a surprise password prompt into a red flag instead of a habit — it's the single highest-leverage change on this page.
- Admin account named generically (e.g.
admin), used only to install software. - Standard account for everything day to day.
- Add time-boxed admin so you can elevate for ~20 minutes when needed, then drop it automatically — SAP Privileges (free, open source) does this.
- Admin account named generically (e.g.
-
Turn on the built-in defenses
Free, already on the machine, and worth doing before you install anything else.
- FileVault — full-disk encryption. Save the recovery key into your password manager.
- Firewall on, Find My on, screen lock required immediately on sleep.
- Confirm System Integrity Protection and a Full Security boot policy are intact (
csrutil status).
3 Harden so it can't sit silently again
The gaps that let it dwell were boring. Close all of them.
No outbound visibility, nothing watching for new persistence, admin-by-default, and secrets sitting in plaintext. None of it exotic — and each one is fixable.
-
Outbound firewall — the exfiltration tripwire
An infostealer's whole job is to phone data out. A per-app outbound firewall is what turns "silent for three months" into "what is this process trying to reach?" Install one, let it learn for a few days, then tighten the rules so your agents and tools can only reach the endpoints they actually use.
- Little Snitch (paid) or LuLu (free, Objective-See) — allow your known traffic, deny the rest.
- For coding agents, scope outbound to the exact API endpoints they need rather than wide-open network access.
-
Persistence monitoring — get alerted the moment something auto-starts
The infection installed auto-start items and nothing flagged it. Fix that so the next attempt is loud.
- BlockBlock (Objective-See) — live alert the instant anything tries to install persistence. Grant it Full Disk Access.
- KnockKnock — run it once for a clean baseline, then weekly. "This is what a clean machine looks like" is the comparison that catches drift.
- On a headless/always-on Mac, swap pop-ups for a file-watch that pushes a phone alert when
/Library/LaunchDaemonsor~/Library/LaunchAgentschanges.
-
Get secrets off disk
The malware read keys because they were sitting in plaintext where anything running as you could reach them. Move them into a vault and inject them at runtime instead.
# Keep keys in a vault; inject per-command instead of leaving them in .env / dotfiles # e.g. with 1Password: op run -- your-command-that-needs-the-key # For automation, use a scoped, read-only service-account token — # revocable and narrow, never your master credentials. -
Hardware-backed 2FA on the accounts that matter
Phishing-resistant 2FA means a stolen password is no longer enough. Register at least two factors per account so losing one doesn't lock you out.
- Hardware security keys (FIDO2) or passkeys on: Apple ID, Google, your Git host, cloud providers, password manager, financial accounts.
- Two keys per account (one carried, one stored safely); keep a passkey as backup. Avoid SMS codes.
-
Supply-chain hygiene for dev tooling
Fast installs are how a lot of these get in. Add friction exactly where it matters.
- Add an install delay so you never pull a brand-new, possibly-poisoned package version the day it ships:
npm install -g npm@latest # need npm 11.10.0+ npm config set min-release-age 7 # wait 7 days before installing a new version- Prefer lockfile-faithful installs (
npm ci) and hash-checked Python installs over loose resolution. - Run untrusted code in a container that does not mount your home directory — your keys shouldn't be reachable from inside the sandbox.
- Never paste a Terminal command from a website, ad, or message. This is the single most common Mac infection trick right now. Download apps only from the maker's official site or the App Store — never a search ad or "mirror."
-
Restore data only — never the hiding spots
The final step is also the easiest to get wrong: bringing the infection back with your files.
- Restore documents, photos, project files, media. Re-clone code from its remote.
- Never restore hidden dotfiles,
LaunchAgents/LaunchDaemons, login items, shell-rc,~/.config,~/.local, app caches, or any.com.apple.*hidden dirs — that's where malware hides. - Reinstall apps fresh from official sources; never restore old
.dmg/.pkginstallers. - Don't reconnect an old external backup drive that was attached during the infection until you've erased it.
Referenced tools
Source links only — install from the original maintainers and stay in control. Nothing here is bundled or redistributed.
Want the fuller playbook?
This checklist is the free, standalone version. If you want the longer write-up — the developer threat model, the full lockdown setup, and the detailed recovery runbook as it comes together — there's a waitlist on the main page. No pressure: the checklist above is yours, ungated, whether you join or not.
See the full story →