7 Mac Security Mistakes Developers Make (And How to Fix Them)
I have been building software on Macs for years. I have also spent the last year building a security tool that scans what is actually happening on macOS under the hood. And the thing that consistently surprises me is not how vulnerable regular users are — it is how vulnerable developers are.
We run more tools, grant more permissions, and install more unsigned code than any other group of Mac users. Our machines are loaded with SSH keys, API tokens, cloud credentials, and access to production infrastructure. And most of us treat security as an afterthought because we assume knowing how computers work means we are safe.
It does not. Here are seven mistakes I see constantly, and how to fix each one.
1. Granting Full Disk Access to Terminal and never thinking about it again
This is the big one. Almost every developer has granted Full Disk Access to Terminal.app, iTerm2, or whatever shell they use. You probably did it the first time a command failed with a permission error, clicked Allow, and moved on with your day.
Here is the problem: Full Disk Access is not scoped to you sitting at your keyboard. It is granted to the Terminal process. That means every script that runs inside that terminal session inherits FDA. Every npm postinstall hook, every shell script you curl and pipe to bash, every AI agent running commands on your behalf — they all get full, unrestricted access to your entire disk.
That includes your Photos library, your Messages database, your Safari history, your Mail data, and every other protected directory that macOS normally locks down.
The fix:
You probably cannot avoid granting FDA to your terminal entirely — too many legitimate dev tools need it. But you can limit the blast radius.
First, be aware of what FDA actually means. It is not just "this app can read files." It is "this app bypasses TCC protections for every protected data category." That should change how casually you run untrusted code in your terminal.
Second, consider running untrusted operations in a sandboxed environment. Docker containers, virtual machines, or at minimum a separate macOS user account that does not have FDA granted. You can check what has FDA right now:
tccutil list com.apple.TCC
Or go to System Settings > Privacy & Security > Full Disk Access and actually look at the list.
2. SSH keys without passphrases
I get it. Typing a passphrase every time you push to GitHub or SSH into a server is annoying. So you generated your key pair with an empty passphrase and called it a day.
The problem is that infostealers — the fastest-growing category of macOS malware in 2025 and 2026 — know exactly where to look. The ~/.ssh/ directory is one of the first places they harvest. If your private key has no passphrase, it is immediately usable by anyone who gets a copy of it. No cracking needed. They have full access to every server and service that key authenticates to.
This is not theoretical. The Atomic Stealer and Cthulhu Stealer families both specifically target SSH keys, and they have been spreading through trojanized developer tools.
The fix:
Add a passphrase to your existing keys:
ssh-keygen -p -f ~/.ssh/id_ed25519
Then configure your SSH agent to cache the passphrase so you only type it once per session:
ssh-add --apple-use-keychain ~/.ssh/id_ed25519
Add this to your ~/.ssh/config so macOS Keychain handles caching automatically:
Host *
AddKeysToAgent yes
UseKeychain yes
This gives you the security of a passphrase-protected key with almost the same convenience as an unprotected one. There is no good reason not to do this.
3. Running npm install on untrusted repos
You find an interesting open source project on GitHub. You clone it. You run npm install. Congratulations — you just executed arbitrary code on your machine with your full user permissions.
npm's postinstall scripts run automatically during installation, and they can do literally anything your user account can do. Read files, make network requests, install additional software, exfiltrate data. The supply chain attack surface in the JavaScript ecosystem is enormous, and it is actively exploited.
This is not just about obviously malicious packages. Typosquatting is real — lodahs instead of lodash, cross-env2 instead of cross-env. Dependency confusion attacks target private package names. And even legitimate packages can be compromised when a maintainer's npm token gets stolen.
The fix:
Before running npm install on any unfamiliar project, check the scripts:
cat package.json | jq '.scripts'
Look for preinstall, install, and postinstall scripts that do anything other than compile native modules. If you see curl, wget, eval, or anything piping to sh, investigate before proceeding.
You can also disable scripts entirely for the initial install and enable them selectively:
npm install --ignore-scripts
Then review what scripts exist and run them manually if they look safe:
npm run postinstall
For ongoing protection, use npm audit regularly and consider tools like Socket.dev that analyze package behavior rather than just known CVEs.
4. API keys in .env files sitting on disk
Every developer has .env files scattered across their project directories. Database connection strings, API keys, AWS credentials, Stripe secret keys, OAuth tokens. We tell ourselves "it is fine, .env is in .gitignore" and stop thinking about it.
But .gitignore only prevents git from tracking the file. The file still exists on your disk, in plaintext, readable by any process running as your user. Infostealers specifically scan for files named .env, .aws/credentials, .ssh/config, .netrc, and similar credential stores. They know the patterns because we all use the same ones.
The fix:
For development, use a secrets manager instead of flat files. macOS Keychain is built in and free:
security add-generic-password -a "dev" -s "STRIPE_SECRET_KEY" -w "sk_test_..."
Retrieve it in scripts:
security find-generic-password -a "dev" -s "STRIPE_SECRET_KEY" -w
For more complex setups, tools like direnv with encrypted .envrc files, 1Password CLI, or Doppler give you secrets management without changing your workflow much.
At minimum, if you must use .env files, restrict their permissions:
chmod 600 .env
This does not stop malware running as your user, but it prevents other user accounts and some categories of information disclosure.
5. Granting AI agents unrestricted access
I use Claude Code every day. It is genuinely transformative for productivity. But running it with --dangerously-skip-permissions or auto-approving everything is the security equivalent of giving a stranger your house keys because they offered to help you move.
AI agents run commands in your terminal. They read and write files across your filesystem. When you auto-approve, you are giving them the same FDA-inherited permissions from Mistake 1, combined with the ability to run any command without your review.
The same applies to OpenClaw skills with broad permissions, MCP servers connected to sensitive APIs, and any other agent framework running locally.
The fix:
Principle of least privilege. For Claude Code, use the default permission model that asks before running commands. Yes, it is slower. The tradeoff is worth it.
For OpenClaw and similar agents, audit the permissions each skill requests before installing:
ls -la ~/.openclaw/skills/
Review the manifest of any skill before granting it access. If a skill asks for file system write access and network access but claims to only generate text, that is a red flag.
For MCP servers, only connect the ones you actively need. Each connected MCP server is an additional attack surface. Disconnect servers you are not using:
claude mcp list
Review what is connected, and remove anything you do not recognize or no longer use.
6. Ignoring brew, pip, and npm audit warnings
You run brew update and see a security advisory. You run pip install and see a deprecation warning about a vulnerable dependency. You run npm audit and see 47 vulnerabilities. You ignore all of them because you are busy shipping features.
Known vulnerabilities in dependencies are the single easiest attack vector against developer machines. They are public knowledge, often with working exploits, and the fix is usually just updating a package. But we consistently deprioritize these because the warnings are noisy and the risk feels abstract.
The fix:
Build auditing into your workflow. Run it, read the output, and actually fix the critical and high severity issues:
npm audit
brew audit --strict
pip audit
For npm specifically, you can auto-fix most issues:
npm audit fix
For issues that require major version bumps and might break things:
npm audit fix --force --dry-run
Review what it wants to change before applying. Set up a weekly reminder if you have to — a calendar event, a cron job, whatever works for you. The point is to make it habitual rather than something you only do when you remember.
7. Never auditing what is actually running on your Mac
Developers install dozens of tools. Homebrew packages, npm global installs, pip packages, VS Code extensions, Docker containers, Raycast plugins, browser extensions, MCP servers, background agents. Each one might spawn background processes, register launch agents, or open network connections.
When was the last time you actually looked at what is running on your Mac?
Open Activity Monitor right now and sort by CPU. You will see processes you do not recognize. Some of them are legitimate system services. Some are helpers for apps you use. And some might be things you installed six months ago, forgot about, and are still running in the background with whatever permissions you granted at install time.
The fix:
Check your launch agents and daemons — these are processes that start automatically:
ls ~/Library/LaunchAgents/
ls /Library/LaunchAgents/
ls /Library/LaunchDaemons/
Review each plist file. If you see something you do not recognize, look up the label online. If it belongs to software you no longer use, unload and remove it:
launchctl bootout gui/$(id -u) ~/Library/LaunchAgents/com.unknown.agent.plist
rm ~/Library/LaunchAgents/com.unknown.agent.plist
Check for login items in System Settings > General > Login Items. Remove anything you do not actively need starting at boot.
And periodically review your Activity Monitor for processes you do not recognize. Sort by network usage — anything making network connections that you did not explicitly start deserves investigation.
The real problem: this is a lot to keep track of manually
I wrote this list and even I find it exhausting. Seven categories of mistakes, each with their own commands to run, directories to check, and habits to build. And this is not even comprehensive — I could easily write seven more.
This is exactly why I built CoreLock. Every single thing on this list — full disk access auditing, background process monitoring, launch agent analysis, permission reviews, network connection tracking — CoreLock does automatically. One scan, and you get a clear report of what is happening on your Mac, what looks suspicious, and what you should fix.
You do not need to remember which directories to check or which commands to run. CoreLock watches everything running on your system and alerts you when something does not look right.
Secure your dev machine in under a minute. Download CoreLock for free at corelock.ai/download and run your first scan. If you are a developer working on a Mac, this is the fastest way to close the gaps you did not know you had.