fix(security)!: disable node scripts by default - #717
Conversation
| run: | | ||
| if [ -f "./cspell.config.json" ]; then | ||
| npx --yes cspell@6.13.3 -c cspell.config.json "**/*.{ts,tsx,js,go,md,mdx,yml,yaml,json,scss,css}" | ||
| npx --yes --ignore-scripts cspell@6.13.3 -c cspell.config.json "**/*.{ts,tsx,js,go,md,mdx,yml,yaml,json,scss,css}" |
There was a problem hiding this comment.
cspell doesn't have any lifecycle scripts for install, so it's safe to always skip the, regardless of the value of node-package-manager-allow-scripts
|
@xnyo stale? |
mckn
left a comment
There was a problem hiding this comment.
Looks great! Some things to consider:
-
Duplicated logic (playwright.yml and actions/internal/plugins/frontend/action.yml) — the entire "Configure package manager script policy" step (~25 lines, including all the comments) is copy-pasted verbatim between the two files. Since it's already the same repo, this could be extracted into a small shared composite action (e.g. actions/internal/plugins/node-install-cmd) that both call, so future fixes/tweaks don't need to be applied twice. Given it's GH Actions and duplication across workflow/action boundaries is common, this is a nice-to-have rather than a blocker.
-
Inconsistent coverage of other npx invocations — npx google-artifactregistry-auth --credential-config ./.npmrc (present in both playwright.yml and frontend/action.yml) still runs without --ignore-scripts, while the cspell npx call in ci.yml was updated. If the goal is blanket protection against malicious install/lifecycle scripts from any npx-fetched package, this call is an inconsistency worth a deliberate decision (even if the answer is "it's a trusted Google package, out of scope").
-
Debug annotation naming is a bit off — the printf '::act-debug::...' lines use ::act-debug:: as if it were a GitHub Actions workflow command, but act-debug isn't a real GH Actions command; it appears to be a convention specific to the act-based test harness (act.AnnotationLevelDebug in the new test) for asserting internal state. Worth a one-line comment noting this is test-harness-only tooling and not a real GHA annotation, so future readers don't mistake it for standard Actions output.
-
Env vars persist for the rest of the job — setting NPM_CONFIG_IGNORE_SCRIPTS/YARN_ENABLE_SCRIPTS via $GITHUB_ENV affects every subsequent step in the job (lint, build, etc.), not just the install step. This is almost certainly intentional ("belt-and-suspenders") and is safe for npm run <script> (explicit run-scripts still execute; only implicit pre/post hooks are suppressed), but it's worth confirming no downstream step in real plugin repos relies on install-time hooks running again mid-job (e.g., a postinstall-triggered codegen step invoked a second time by a later npm install).
-
TODO acknowledged, not blocking: the test file has an explicit TODO noting Yarn Berry's --ignore-scripts-rejection path isn't covered by a real fixture yet — reasonable to leave as follow-up given no simple-frontend-yarn-berry fixture currently exists, but worth a tracking issue so it doesn't get forgotten given it's the one CLI-flag branch with no test coverage today.
Disables scripts before running npm/yarn/pnpm install in the frontend action and playwright action. This improves security and protects against npm supply chain attacks that use pre-install, install or post-install scripts to inject malicious payloads.
If those scripts are required, the new
node-package-manager-allow-scriptsinput can be used to restore the old behavior.For repositories using pnpm, a better approach than using
node-package-manager-allow-scriptsis to allowlist only the specific packages that genuinely need build scripts, reducing the blast radius. The setting to use depends on the pnpm version:pnpm ≤9 and pnpm 10 (before 10.26) — add to
package.json:{ "pnpm": { "onlyBuiltDependencies": ["esbuild", "sharp"] } }pnpm 10.26+ — add to
pnpm-workspace.yaml:pnpm 11+ — same as above (
onlyBuiltDependenciesis removed in pnpm 11,allowBuildsis the only supported option):