Skip to content

fend

Sandbox npm install. Stop trusting it.
v0.1.0-alpha →

A sandboxed runtime for npm install, npm run dev, and friends. Your project dependencies execute in a micro-VM with zero access to your home directory, credentials, or anything else outside the project folder.

Terminal window
npm install -g @fendsh/cli

Requires macOS 13+ on Apple Silicon. The CLI is open source — browse the source.

The threat

Every npm install runs arbitrary code as you

Section titled “Every npm install runs arbitrary code as you”

Three classes of attack are now routine in the npm ecosystem. All three end the same way — arbitrary code, executed under your user, with full access to everything you can touch.

Typosquatting

A package named react-domm waits in the registry. One typo and its postinstall hook reads ~/.ssh/id_rsa to a remote endpoint.

Maintainer takeover

A trusted dep changes hands and its next minor release is malicious. Happened to event-stream, to colors, to node-ipc. Will happen again.

Dependency confusion

A private package name gets registered in the public registry. Your install silently pulls the attacker’s version.

What fend actually blocks

A malicious postinstall can’t reach what isn’t there

Section titled “A malicious postinstall can’t reach what isn’t there”

Without fend

$ npm install evil-pkg
> [email protected] postinstall
> node ./steal.js
exfiltrated /Users/you/.ssh/id_rsa
exfiltrated /Users/you/.aws/credentials
added launchd persistence
added 1 package

With fend

$ fend npm install evil-pkg
fend: ready (0.8s)
> [email protected] postinstall
> node ./steal.js
Error: ENOENT /Users/you/.ssh/id_rsa
Error: ENOENT /Users/you/.aws/credentials
Error: EACCES launchctl
added 1 package

Same package, same script — no SSH keys to steal because the VM never had access to ~/.ssh. Recording of the live demo coming soon.

How it works

your shell micro-VM (Linux)
────────── ────────────────
$ fend npm install ──┐ ┌─ npm install runs here
│ │
▼ │ • sees /workspace (= your project dir)
[ fend ] │ • sees /root/.npm (host npm cache)
│ │ • sees the network
boots / reuses ─────────►│ • sees nothing else from your Mac
warm VM (~800ms │
cold, ~5ms warm) │ /home/you/.ssh → does not exist
│ │ /home/you/.aws → does not exist
◄───────── stdout/stderr │ /home/you/Library → does not exist
└─ writes node_modules/ back via VirtioFS

Built on Apple Virtualization.framework — the same hypervisor OrbStack and Apple Containerization use. Sub-second cold boot, instant warm dispatch, auto-pause after 5 min idle.

Two layers of defense

Micro-VM sandbox

Every command runs inside a per-project Linux micro-VM with VirtioFS mounting only your project directory. The VM cannot read ~/.ssh, ~/.aws, ~/Library, ~/.gnupg, or any .env file outside the project.

Boots in ~800ms, warm dispatch in ~5ms, pauses after 5 min idle.

OSV.dev audit on every install

Before lifecycle scripts run, fend queries OSV.dev for known advisories against your package-lock.json — one batch round trip, cached per advisory.

Blocks malware and critical outright. Prompts on high. Configurable in .fend.toml. fend audit --fix upgrades and writes overrides for you.

Sandbox boundary

  • Your project directory (read-write, via VirtioFS)
  • The npm cache (~/.fend/cache/npm/)
  • The runtime overlay (read-only — Node, Bun, Python)
  • The network (NAT, full internet for package downloads)
  • A small allowlist of env vars: TERM, LANG, LC_*, EDITOR, GIT_AUTHOR_*, GIT_COMMITTER_*, COLORTERM, NO_COLOR, FORCE_COLOR
  • ~/.ssh/ — SSH keys
  • ~/.aws/ — AWS credentials
  • ~/Library/ — Keychain, browser data, cookies
  • ~/.gnupg/ — GPG keys
  • .env files outside the project directory
  • Any other project on your machine
  • AWS_*, GITHUB_TOKEN, NPM_CONFIG_*, ANTHROPIC_*, CLAUDE_*, HTTP(S)_PROXY, SSH_AUTH_SOCK env vars

Need to inject a token explicitly? Use —env KEY=VALUE or —env-file — values stay in process memory, never written to the VM filesystem. Full reference →

vs. the alternatives

Sandboxes executionCatches known CVEsWorks with npm/bun/pnpmNative IDE experience
fend✓ (OSV.dev)✓ (VirtioFS)
npm auditpartial (npm DB)
Socket.dev✗ (alerts only)
Deno permissionsruntime flagsDeno-only
Dev Containersremote-extensions only
Just running it

fend is complementary to detection tools like Socket.dev. Detection tells you something looks suspicious. fend makes it not matter if it’s malicious.

Quickstart

Terminal window
# 1. Install
npm install -g @fendsh/cli
# 2. Use it as a prefix
fend npm install
fend npm run dev
# 3. Or hook your shell so you can drop the prefix
echo 'eval "$(fend hook zsh)"' >> ~/.zshrc
fend on # npm/bun/pnpm/yarn/node now route through fend
npm install # sandboxed
fend off # back to normal