Sandboxing Untrusted Code on macOS
Every npm install, every cloned repo, every AI-generated script is a potential attack vector. Here's how to run untrusted code on your Mac without risking your data, credentials, or sanity.
The Threat Model
Before choosing an isolation strategy, you need to understand what you're protecting against. Most developers face three categories of risk:
1. Supply Chain Attacks
That innocent-looking npm package? It might run arbitrary code during installation. In 2024 alone, thousands of malicious packages were discovered on npm, PyPI, and other registries. The postinstall script in a dependency's dependency can:
- Read your SSH keys and environment variables
- Exfiltrate browser cookies and credentials
- Install persistent backdoors
- Encrypt files for ransom
2. Untrusted Repositories
Cloning a GitHub repo to "just try it out" means running someone else's build scripts, test runners, and git hooks. Even reviewing code in VS Code can trigger malicious extensions or workspace settings.
3. AI-Generated Code
AI coding assistants and agents produce code you haven't reviewed. When an agent runs npm install or executes shell commands, you're trusting both the AI and every package it chose to depend on. This is a rapidly growing attack surface.
The uncomfortable truth
If malicious code runs on your Mac with your user privileges, it has access to everything you do: your documents, your browser sessions, your cloud credentials, your SSH keys. macOS sandboxing for App Store apps doesn't help here — you're running code directly.
Isolation Options on macOS
Let's evaluate the realistic options for isolating untrusted code on macOS:
Separate User Accounts
Isolation level: Low
You can create a separate macOS user for untrusted work. This provides filesystem isolation but shares the same kernel, network stack, and hardware. Malware can still:
- Exploit kernel vulnerabilities
- Access network resources
- Interact with other processes via IPC
Verdict: Better than nothing, but not real isolation.
Docker Containers
Isolation level: Medium (on Linux), Low (on macOS)
Docker on macOS runs a Linux VM under the hood (via Apple's Virtualization.framework or QEMU). Your containers run inside that Linux VM, which means:
- You can't run macOS software in containers
- GUI apps don't work
- You're isolated from macOS, but you're sharing a Linux kernel with all other containers
Docker is great for deploying Linux services, but it's not a macOS sandbox. If you need to test macOS-specific behavior, run Xcode, or use native Mac tools, containers won't help.
Verdict: Good for Linux workloads. Not a macOS isolation solution.
macOS Virtual Machines
Isolation level: High
A full macOS VM provides the strongest isolation available on Apple Silicon. Each VM has:
- Its own kernel instance
- Separate filesystem and user data
- Isolated network identity
- No access to host files (unless explicitly shared)
Even if malware achieves root access inside the VM, it cannot escape to the host without a hypervisor vulnerability (extremely rare).
Verdict: The right choice for running untrusted macOS code.
Why VMs Beat Containers for macOS Isolation
| Capability | Docker | macOS VM |
|---|---|---|
| Run macOS apps | No | Yes |
| Run Xcode / Swift | No | Yes |
| GUI support | No | Yes |
| Kernel isolation | Shared Linux kernel | Separate kernel |
| Network isolation | Configurable | Full NAT isolation |
| Snapshot / rollback | Image layers | Full disk snapshots |
| Startup time | Seconds | 30-60 seconds |
The startup time tradeoff is real, but for security-sensitive work, it's worth it. And with modern Apple Silicon, VM boot times are fast enough for practical use.
Real-World Scenarios
Scenario 1: Evaluating a Random GitHub Project
You found a cool tool on GitHub. The README says "just run make install". But you've never heard of this developer, and the repo has 47 stars.
Safe approach: Clone and build inside a sandboxed VM. If the Makefile does something sketchy, your host Mac is unaffected. If it's legit, you can either keep using the VM or install it on your host with confidence.
Scenario 2: Running npm install on a New Project
You're about to work on a client's codebase. The package.json has 200+ dependencies, and you have no idea what's in the dependency tree.
Safe approach: Run npm install in a VM with no access to your SSH keys, credentials, or sensitive files. Share only the project folder (read-only if possible).
Scenario 3: Letting an AI Agent Code for You
You're using an AI coding agent that can execute shell commands and install packages. The agent is helpful, but you don't want it to have access to your entire system.
Safe approach: Give the agent access to a sandboxed VM workspace. It can install packages, run tests, and modify code — all isolated from your host. If something goes wrong, revert to a clean snapshot.
A Practical Sandboxing Workflow
Here's a workflow for running untrusted code using macOS VMs:
1. Create a Base VM
Set up a clean macOS VM with your development tools: Xcode CLI, Node, Python, Homebrew, etc. This is your template.
# Create a new VM
vmctl init ~/VMs/dev-template.GhostVM --cpus 4 --memory 8 --disk 64
vmctl install ~/VMs/dev-template.GhostVM
vmctl start ~/VMs/dev-template.GhostVM
# Install your tools inside the VM, then shut down
vmctl stop ~/VMs/dev-template.GhostVM
# Create a "clean" snapshot
vmctl snapshot ~/VMs/dev-template.GhostVM create clean-state2. Clone for Each Untrusted Project
When you need to work on something untrusted, clone the template. APFS copy-on-write makes this instant and space-efficient.
# Clone the template (instant, ~0 disk overhead)
# In the GUI: right-click the VM → Clone
# Or use Finder to duplicate the .GhostVM bundle3. Work in Isolation
Start the cloned VM and do your untrusted work there. Use shared folders (read-only) to access project files if needed.
# Start with a shared folder
vmctl start ~/VMs/untrusted-project.GhostVM \
--shared-folder ~/Projects/client-repo --read-only4. Revert or Dispose
When you're done, either revert to the clean snapshot or delete the VM entirely. Nothing persists to your host.
# Option A: Revert to clean state
vmctl snapshot ~/VMs/untrusted-project.GhostVM revert clean-state
# Option B: Delete the VM entirely
rm -rf ~/VMs/untrusted-project.GhostVMThe Bottom Line
If you're a developer on macOS, you're running untrusted code regularly — every npm install, every pip install, every brew install. Most of the time it's fine. But when it's not, the consequences can be severe.
macOS virtual machines give you real isolation: separate kernel, separate filesystem, separate network identity. They're the practical answer to "how do I run this without risking my machine?"
GhostVM: Built for This
GhostVM is a free, open-source Mac VM app designed for exactly this workflow. Instant cloning, snapshots, shared folders, and a scriptable CLI for automation.