LavaMoat Node.js runtime
lavamoat
is a Node.js runtime where modules are defined in SES Compartments. It virtualizes CommonJS module loading to apply runtime protections according to a Policy.
LavaMoat Runtime
LavaMoat differs from the standard node runtime in that it:
- Uses
lockdown()
from SES to prevent tampering with the execution environment. Thanks to lockdown, prototype-pollution attacks are neutralized. It’s also a prerequisite to code isolation. - Uses SES Compartments to isolate each package’s execution.
Packages don’t share references to anything unless explicitly passed in or allowed by policy. Custom
require
and linking implementation is provided for the purpose of loading allowed dependencies. - Enforces the app-specified LavaMoat policy. The policy specifies what execution environment each package should run with, which means: what global/built-in APIs should it be exposed to, and what other packages can it require.
The result is a runtime that should work just as before, but provides some protection against supply chain attacks.
Install
Use one of:
npm i lavamoatyarn add lavamoat
Usage
- Install
- Run your application once with
lavamoat app.js --autopolicy
- Inspect the
./lavamoat/node/policy.json
file it generated - Run your application with
lavamoat app.js
- If you find you need to change the policy in step 2 or 3 create a
./lavamoat/node/policy-override.json
file and introduce changes there. You can both expand and trim the permissions.
For multiple entry points or apps, use the options to set policy paths to maintain policies specific to each app.
For more information on the lavamoat policy file, check Policy file explained in documentation.
All options
lavamoat <entryPath> [Options]
Positionals: entryPath the path to the entry file for your application. same as node.js [string]
Options: --version Show version number [boolean] --help Show help [boolean] -p, --policy, --policyPath Pass in policy. Accepts a filepath string to the existing policy. When used in conjunction with --autopolicy, specifies where to write the policy. Default: ./lavamoat/node/policy.json [string] [default: "lavamoat/node/policy.json"] -o, --policyOverride, --override, Pass in override policy. Accepts a --policyOverridePath filepath string to the existing override policy. Default: ./lavamoat/node/policy-override.json [string] [default: "lavamoat/node/policy-override.json"] --policyDebug, --pd, --policydebug, Pass in debug policy. Accepts a --policyDebugPath filepath string to the existing debug policy. Default: ./lavamoat/node/policy-debug.json [string] [default: "lavamoat/node/policy-debug.json"] -a, --writeAutoPolicy, --autopolicy Generate a "policy.json" and "policy-override.json" in the current working directory. Overwrites any existing policy files. The override policy is for making manual policy changes and always takes precedence over the automatically generated policy. [boolean] [default: false] --writeAutoPolicyAndRun, --ar, parse + generate a LavaMoat policy --autorun file then execute with the new policy. [boolean] [default: false] --writeAutoPolicyDebug, --dp, when writeAutoPolicy is enabled, --debugpolicy write policy debug info to specified or default path [boolean] [default: false] --projectRoot specify the director from where packages should be resolved [string] [default: "/home/naugtur/work/metamask/metamask-extension"] -d, --debugMode, --debug Disable some protections and extra logging for easier debugging. [boolean] [default: false] --statsMode, --stats enable writing and logging of stats [boolean] [default: false]
Examples
Run with Policy in default location
This uses the existing policy and policy-override files to run your app.
lavamoat index.js
Automatically searches for policy files inside ./lavamoat/node/
.
Policy Override with Relative Path
This uses the override policy specified at ./policies/policy-override.json
.
lavamoat index.js --override './policies/policy-override.json'
Troubleshooting
-
Having trouble reading thrown Errors? try running with the
--debugMode
flag. Warning: not safe for production runs. -
Got a dependency that wont quite work under LavaMoat? try patch-package
For more details go to the troubleshooting section
Programmatic usage
Programmatic usage is almost identical to the commandline and its arguments.
const { runLava } = require('lavamoat');
runLava({ entryPath: './app.js', // Optional: writeAutoPolicy: false, writeAutoPolicyDebug: false, writeAutoPolicyAndRun: false, policyPath: 'path to file', policyDebugPath: 'path to file', policyOverridePath: 'path to file', projectRoot: process.cwd(), debugMode: false, statsMode: false,});