# LavaMoat: three tools that shrink what your dependencies can reach

> LavaMoat is a set of JavaScript tools for supply chain defence: allow-scripts blocks install scripts by default, and a SES-based runtime confines each package to a policy that limits platform API access.

**LavaMoat/LavaMoat** — tools for sandboxing your dependency graph

- Repository: https://github.com/LavaMoat/LavaMoat
- Website: https://lavamoat.github.io/
- Stars: 1,241 · Forks: 85
- Language: JavaScript
- License: MIT
- Published: 2026-10-19 · Updated: 2026-10-19 · Language: en
- Canonical page: https://hysenlabs.com/projects/lavamoat-lavamoat

## Three stages of the software lifecycle, three separate tools

LavaMoat is a set of tools for securing JavaScript projects against software supply chain attacks, where a malicious dependency makes its way into a developer's application and then steals secrets such as credit card numbers or private keys, or makes the application vulnerable in other ways.

The attack class is not hypothetical. The project notes that these attacks have already hit the cryptocurrency ecosystem and present a significant risk to the developers and users of wallets and apps.

The design principle is that the risk exists at several points in the lifecycle, so the protection is split across several points. The suite tackles supply chain security at the installation of the package, at build time, and most of all at runtime.

Concretely, there are three steps to secure an app:

```bash
# 1. disable/allow dependency lifecycle scripts (eg. "postinstall")
# 2. run your server or build process in lavamoat-node
# 3. build your ui with LavaMoat for Browserify
```

The stated goal is to bring added protections to modern JavaScript apps without having to rewrite them from scratch, and to automate a good first-start security configuration. That second half matters: a security tool that requires a hand-written policy for four hundred dependencies will not be adopted, so the first-run configuration is the part that makes the rest possible.

The project also makes the point that you do not have to adopt all of it. Adding just step 1, the allow-scripts tool, is described as a great improvement to your supply chain security on its own.

The project is MIT licensed, is made with love by MetaMask, is funded by ConsenSys, and runs on Agoric. The repository is not archived and the last push was on 2026-10-19, with recent releases including webpack v3.0.1, preinstall-always-fail v3.0.1 and node v2.0.1, all on 2026-10-09.

## allow-scripts makes postinstall opt-in instead of opt-out

The install scripts stage is the most popular attack vector for malicious packages in recent years, and allow-scripts is the tool that closes it.

Its mechanism is a configuration change rather than a sandbox. LavaMoat's allow-scripts configures your project to disable running install scripts by default, and gives you a configuration section in package.json where the allowed ones can be listed. No new install scripts showing up in your dependencies will run unexpectedly.

The second part is the clever bit. It also installs a package with an install script that fails installation as early as possible if the configuration is accidentally removed. So if a developer deletes the configuration, or a merge drops it, the install breaks loudly at that point rather than silently restoring the unsafe default. That failure package is a separate published package, preinstall-always-fail, which is visible in the release list at version v3.0.1.

The practical effect is that the postinstall script of every dependency stops running unless you have explicitly looked at it and allowed it. For most projects that is dozens of scripts, most of which build native binaries or download platform-specific packages, so the work is real but bounded, and the alternative is running arbitrary code from every package in the tree at install time.

Because this is a package.json configuration rather than a runtime mechanism, it also applies to every developer on the team and to CI, without changing how the application runs.

## The runtime confines each package to what the policy grants

The runtime stage is where LavaMoat does more than block install scripts, and it works by preventing malicious code introduced into a package from running.

The runtime reduces the supply chain risk in two ways. It prevents modifying JavaScript's primordials, meaning Object, String, Number and Array, and it limits access to the platform API, window, document, XHR and so on, per package.

Both are provided by SES containers. SES, Secure EcmaScript, is the sandbox used in LavaMoat, and it has its own secure computing guide for the risks of untrusted JavaScript. The lockdown that SES performs is what makes the primordials unmodifiable, and the lockdown that removes the global scope is what makes per-package platform access enforceable.

Platform API access is granted by a policy file that LavaMoat can generate, and the project allows you to selectively customise it. The structure of that file is documented in the policy file explained document under docs/policy.md, so the generated file is meant to be read and edited rather than treated as an opaque artifact.

In Node.js the entry point is lavamoat-node, which is how you run your server or your app building code with the protections on. In the browser, you can use your favourite bundler if a plugin is available, and the project ships a Browserify plugin.

The bundler side has its own structural requirement, and it is worth understanding. An app bundle has two major components: the runtime, also called the kernel, loader, prelude or trusted computing base, which is the code that initialises and runs the bundle such as the implementation of require, and the module sources, which are the JavaScript content of the modules plus sometimes configuration such as module name aliases. LavaMoat modifies the bundle's runtime to enforce the configured constraints, which is why the security lives in the loader rather than in each module.

## Scuttling is the advanced option, and it is off by default

Beyond the baseline protection there is an optional feature called scuttling, described as a further and advanced security enhancement to LavaMoat protection which is off by default and can enhance the security LavaMoat applies to your application.

The instruction before using it is specific: get yourself familiar with it and with the implications of using it by reading its doc file, docs/scuttling.md.

The fact that it ships disabled and carries its own document tells you something about how it works. The baseline runtime protections are designed to be applied without the developer having to think about them. Scuttling changes something about the execution environment in a way that can break code, so the guidance is to understand it first rather than to flip it on.

One related tool in the project deserves a warning label of its own. lavamoat-viz is a tool to visualise an application's dependency graph and assess its security risk, and it carries a warning that it is currently unmaintained, with tentative plans to resume development in the future. It lives on its own branch in the repository, lavamoat-viz, and it is the tool you would reach for first to understand what you are dealing with, so knowing it is not maintained matters.

The further reading section in the documentation points at concrete incidents rather than theory, including an Agoric write-up on how the POLA object-capability approach would have prevented the event-stream incident, and an Snyk piece on why npm lockfiles can be a security blind spot for injecting malicious modules. The videos include Kate Sills on making npm install safe, and a talk on object-capability security for JavaScript applications from KU Leuven.

## The monorepo, and the tools around the packages

The repository is a Yarn or npm workspace monorepo, lavamoat-monorepo, with the packages under packages/*, and the individual tools are separate published packages: lavamoat-node, the browserify plugin under packages/browserify, and allow-scripts under packages/allow-scripts.

The root package.json shows the tooling conventions, and they are the kind you would want in a security project, where the build pipeline is part of the trust boundary. The Node engine requirement is ^22.22.2 || ^24.15.0 with npm >=7.0.0. The lint script is not a single command but four: eslint, a dependency lint run per workspace, a lockfile lint through a custom script at scripts/lint-lockfile.js, and an engines check using installed-check with --engine-check. The lockfile lint is the interesting one for supply chain work, because a lockfile is exactly what an attacker would want to modify.

Commit messages are linted with commitlint, the configuration is commitlint.config.js, and releases are managed with release-please, with a .release-please-manifest.json and release-please-config.json, and the release script runs a rebuild and a test pass before publishing through a tool called laverna. The test script builds first, then runs test:prep and test:workspaces across the workspaces.

There is a .husky directory with a setup script that installs the hooks, a socket.yml, and the repository has SECURITY.md, CODE_OF_CONDUCT.md, CONTRIBUTING.md, a RELEASE.md and an AGENTS.md. The presence of a .nvmrc pinning the Node version and a .wallaby.cjs for test watching both point to a project where the local environment is expected to match the CI one closely, which is the right stance when the build is what enforces the security.

## Conclusion

LavaMoat fits a JavaScript team that ships to browsers or runs a Node service and wants the same dependency graph reviewed and restricted, and that accepts a build step and a policy file in exchange. It is a poor fit for a project with no untrusted dependencies, since the lockdown and the policy work buys nothing there, and it is a poor fit if you need the free-form platform access some packages expect. Before adopting, start with allow-scripts alone, since the documentation calls that a large improvement on its own, and read the scuttling document before turning that optional feature on, because it is off by default for a reason.

## FAQ

### What is LavaMoat and what problem does it solve?

LavaMoat is a set of tools for securing JavaScript projects against software supply chain attacks, where a malicious dependency makes its way into a developer's application and then steals secrets or opens other vulnerabilities. The tools aim to tackle supply chain security at several stages of the software lifecycle: at installation of the package, at build time and at runtime.

### How do I use the LavaMoat allow-scripts tool?

allow-scripts configures your project to disable running install scripts by default and adds a configuration section in package.json where the allowed ones can be listed. It also installs a package with an install script that fails installation as early as possible if the configuration is accidentally removed.

### What protections does the LavaMoat runtime provide?

It prevents modifying JavaScript's primordials such as Object, String, Number and Array, and it limits access to the platform API, including window, document and XHR, per package. Both are provided by SES containers, and platform access is granted by a policy file that LavaMoat can generate and that you can customise.

### What is scuttling in LavaMoat?

Scuttling is an optional further security enhancement to the LavaMoat protection. It is turned off by default, and the project advises getting familiar with it and the implications of using it by reading docs/scuttling.md before turning it on.

### Is lavamoat-viz still maintained?

No. The project carries a warning that lavamoat-viz is currently unmaintained, with tentative plans to resume development in the future. It is the tool for visualising an application's dependency graph and assessing its security risk, and it lives on its own branch in the repository.

## Sources

- [LavaMoat/LavaMoat on GitHub](https://github.com/LavaMoat/LavaMoat)
- [License: MIT](https://github.com/LavaMoat/LavaMoat/blob/main/LICENSE)
- [Project website](https://lavamoat.github.io/)
- [README](https://github.com/LavaMoat/LavaMoat/blob/main/README.md)
- [Releases](https://github.com/LavaMoat/LavaMoat/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/lavamoat-lavamoat
