Skip to content

chore: integrate LavaMoat/harden - #9937

Draft
Mrtenz wants to merge 1 commit into
mainfrom
mrtenz/harden
Draft

chore: integrate LavaMoat/harden#9937
Mrtenz wants to merge 1 commit into
mainfrom
mrtenz/harden

Conversation

@Mrtenz

@Mrtenz Mrtenz commented Aug 24, 2026

Copy link
Copy Markdown
Member

Explanation

Scripts run through yarn run currently execute with the full ambient authority of the developer's shell: unrestricted filesystem access, network access, the ability to spawn child processes, and access to every environment variable including credentials. A compromised dependency that gets to run any lifecycle or package script therefore has a straightforward path to exfiltrating secrets or tampering with files outside the repository.

This PR integrates the LavaMoat/harden setup, ported from MetaMask/metamask-module-template.

It adds a lavamoat/ directory containing:

  • Script permission configs with secure defaultsscripts.strict.json (deny all powerful IO capabilities), scripts.loose.json (a more permissive variant for scripts that genuinely need native capabilities), and scripts.skills.json (used by skills:postinstall).
  • .env.ban.json — a list of keywords used to filter sensitive environment variables out of the script environment.
  • .runner-plugin.js — a Yarn 4 plugin that hooks wrapScriptExecution and applies the above. For every script it resolves the matching config from the workspace's scriptsConfig field, translates it into Node's permission model flags via NODE_OPTIONS, strips banned environment variables, and moves node_modules/.bin to the end of PATH to eliminate bin confusion attacks.
  • plugin-allow-scripts.js — the LavaMoat allow-scripts plugin, now vendored locally rather than fetched from a remote URL at install time.

Every workspace declares scriptsConfig.#default pointing at the strict config, and a new Yarn constraint in yarn.config.cjs enforces that this stays in place for newly added packages.

Some changes whose purpose may not be obvious:

  • .nvmrc is pinned to Node 26 — the permission model flags used here require a recent runtime.
  • .npmrc and .yarnrc are added — these make accidental use of npm or Yarn 1 safe (ignore-scripts, offline), since neither honours the Yarn 4 plugin.
  • enableHardenedMode: true in .yarnrc.yml validates lockfile content against the remote registries.
  • enableMirror: false and globalFolder: .yarn/global — despite enableGlobalCache being disabled, Yarn still writes to the global folder, so it is redirected into the project to stay within the permitted write scope.
  • lavamoat/ is excluded from ESLint and oxfmt — the plugin sources are vendored from upstream and are intentionally kept unmodified so they remain easy to diff against the template.

References

Based on MetaMask/metamask-module-template#335

Checklist

  • I've updated the test suite for new or updated code as appropriate
  • I've updated documentation (JSDoc, Markdown, etc.) for new or updated code as appropriate
  • I've communicated my changes to consumers by updating changelogs for packages I've changed
  • I've introduced breaking changes in this PR and have prepared draft pull requests for clients and consumer packages to resolve them

Add the `LavaMoat/harden` setup, based on
MetaMask/metamask-module-template#335.

This introduces a `lavamoat/` directory with config files containing
secure defaults for running scripts (`scripts.strict.json`,
`scripts.loose.json`, and `scripts.skills.json`), plus a banned
environment variable list, and a Yarn runner plugin that applies them.
The plugin wraps every `yarn run` script with Node's permission model,
restricting filesystem, network, child process, worker, addon, WASI,
and inspector access, filters sensitive environment variables out of
the script environment, and moves `node_modules/.bin` to the end of
`PATH` to prevent bin confusion attacks.

Each workspace now declares `scriptsConfig.#default` pointing at the
strict config, enforced by a new Yarn constraint. Yarn hardened mode is
enabled, `.npmrc` and `.yarnrc` are added to make accidental npm or
Yarn 1 usage safe, and Node is pinned to 26 since the permission model
requires a recent runtime.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant