Skip to content

Harden your local development environment

Updated: 2026-05

This document lists the low-hanging-fruit settings you can put in place to make your local development environment more resistant to compromise when working with the Web ecosystem. This is not defense-in-depth, but rather provides the most bang-for-your-buck against supply chain attacks and other common attack vectors in the ecosystem.

Malware avoidance defaults

This section explains how to configure your project to prevent dangerous package manager behavior.

npm

For npm you should put a default .npmrc in your home folder; this configuration will be consulted whenever the project doesn’t have one. Create this, and create one for every project.

.npmrc
## Ignore all lifecycle scripts by default. You can
## still allow them on a per-package basis with
## @lavamoat/allow-scripts
ignore-scripts=true
# Avoid installing packages published in last 2 days
min-release-age=3
## Don't install packages from git urls, which can
## be used to bypass the above two settings
allow-git=none
## allow direct git dependencies only
# allow-git=root
## Enable this if you never want to use git dependencies
## Break git usage for older npm versions that don't
## support allow-git and repositories that override it
# git=false
## Don't install packages without asking (only
## applicable to old npx versions)
install=false
## enable this if you don't really use npm and want to
## avoid consequences of some script calling npm or npx
## Don't install packages unless they're in local cache
# offline=true
## Don't put commands from packages in PATH
# bin-links=false

Yarn

Upgrade to Yarn 4.14+ which adds the approvedGitRepositories setting.

Once you add the setting, earlier versions of Yarn 4.x will complain about an unknown field, so it’ll be hard to miss you’re not on the right version.

.yarnrc.yml
## Don't run lifecycle scripts by default. You can still
## allow them on a per-package basis with @lavamoat/allow-scripts
enableScripts: false
## Allowlist of git dependencies. Empty to block all git deps.
approvedGitRepositories: []
## Avoid installing packages published in last 3 days
npmMinimalAgeGate: 4320 # 3 days (in minutes)
## Override the minimal age gate, allowing certain packages
## to be installed regardless of their publish age.
#npmPreapprovedPackages:
# - '@yournamespace/*'
## This one is a bit paranoid
## disable global cache to avoid cross-project poisoning
enableGlobalCache: false

In case a contributor attempts to use the wrong Yarn version, you need to avoid Yarn v1.x running the lifecycle scripts.

.yarnrc
ignore-scripts true

pnpm

You’re pretty much set, if you’re on pnpm 11+.

You can still use @lavamoat/allow-scripts for the allow-list with version management, but pnpm is equally good.

pnpm-workspace.yaml
## Avoid installing packages published in last 3 days
minimumReleaseAge: 4320 # 3 days (in minutes)
## Override the minimal age gate, allowing certain packages
## to be installed regardless of their publish age.
# minimumReleaseAgeExclude:
# - '@yournamespace/*'
## Selectively run lifecycle scripts
# allowBuilds:
# package@VERSION: true
# package@VERSION || ANOTHERVERSION: true
## This might prevent some cases of package takeover, but
## will also react to maintainers publishing versions inconsistently
## Fail if trusted publishing or provenance is gone from a
## package that used to have it
trustPolicy: no-downgrade
## Only if you're still on pnpm v10
# blockExoticSubdeps: true # block git and file dependencies of dependencies

Securely Running Lifecycle Scripts

If you need to allow lifecycle scripts for some packages, use @lavamoat/allow-scripts to set up a per-package allowlist. It identifies packages with their position in the dependency tree, so if you allow one package, scripts from different packages that match the name will not run. (git and bundled dependencies declare their own name in pacage.json to be whatever they want)

For more information, see the complete @lavamoat/allow-scripts guide.

If You Absolutely Must Use Git Dependencies

If you must use git dependencies, there’s a tool to help you validate they’re being used as safely as possible: @lavamoat/git-safe-dependencies.

@lavamoawt/git-safe-dependencies is a CLI tool which validates Git dependencies against a set of opinionated rules.

Fundamental secrets hygiene

  1. Use a password manager

  2. Enable 2fa on your npmjs.com account (even if you don’t publish from localhost)

  3. Protect your ssh keys A: Configure an ssh agent with a password protected key

    • An ssh agent will help avoid needing to enter the password every time you use the key.
    • Make your existing ssh key hard to crack with the -a option. Set iterations to 1024 instead of 16 (it will take a few seconds to unlock, but you can survive that once a day)
    Terminal window
    ssh-keygen -p -a 1024 -t ed25519 -f ~/.ssh/id_ed25519

    B: If you’re a 1Password user, use the ssh-agent from 1Password and keep your keys there. Works best if you need to tap the fingerprint reader every time your key is used.

    • 1Password ssh-agent
    • (please suggest other password managers that have a good locked-by-default ssh agent)
  4. Don’t give secrets to AI agents. Don’t run highly-privileged agents (e.g., Openclaw) on the same machine as your development environment.

  5. Avoid storing plaintext secrets, even for unimportant testing environments, in .env files or similar. If you have to put them there while you’re testing, make sure to delete them ASAP and only store them permanently in a password manager.

Get early warnings

You can install Socket Firewall to prevent known malware from being installed on your machine. In some cases it can detect malware that’s still active on the npm registry.

Proactive compartmentalization

We’ve eliminated the most popular install-time compromise vectors by this point, but that’s not the only time you run someone else’s code in your dev environment. What about when you run npm run build or yarn lint? It’d be great to have a virtual dev environment for every project or find a way to consistently use tools like:

  • docker sandbox on any OS
  • firejail or bubblewrap on Linux
  • windows-sandbox on Windows

…but without giving up on the developer experience (if you already do, feel free to skip this part).

Remember, we’re focusing on low-effort high-reward solutions here.

Kipuka

Kipuka is an experimental tool, that - once installed - transparently wraps every use of your package manager in a Docker container.

You can use it to:

  • Avoid exposing your entire OS and filesystem to the code that runs when you npm run lint or yarn build, etc. It aliases your package manager and runs the container transparently, so you don’t have to change the workflow you’re used to.
  • Quickly spin up a container to run commands in the current folder in isolation.
  • Customize your container without learning all the details of how a Dockerfile works

See the Kipuka README for installation instructions and usage details.