Skip to content

fix(security): replace npx with npm exec in pre-commit hook #79

Merged
frankieyan merged 1 commit intomainfrom
frankie/remove-npx
Apr 4, 2026
Merged

fix(security): replace npx with npm exec in pre-commit hook #79
frankieyan merged 1 commit intomainfrom
frankie/remove-npx

Conversation

@frankieyan
Copy link
Copy Markdown
Member

Overview

npx can silently fetch and execute packages from the npm registry if a matching local install is missing or if a package name is typosquatted. Since lint-staged is already an explicit devDependency, using npm exec instead ensures we only run the locally installed version, closing a potential supply-chain attack vector.

Test plan

  • Stage a file with a lint issue and commit
    • lint-staged runs and catches the issue
  • Stage a clean file and commit
    • Commit succeeds normally

🤖 Generated with Claude Code

`npx` can fetch and execute unverified packages from the registry if a
local install is missing or typosquatted. `npm exec` with an already
installed devDependency avoids that risk.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@frankieyan frankieyan requested a review from a team as a code owner April 4, 2026 09:14
@frankieyan frankieyan requested review from scottlovegrove and removed request for a team April 4, 2026 09:14
@frankieyan frankieyan changed the title Replace npx with npm exec in pre-commit hook fix(security): replace npx with npm exec in pre-commit hook Apr 4, 2026
@frankieyan frankieyan added the 👀 Show PR PR must be reviewed before or after merging label Apr 4, 2026
Copy link
Copy Markdown
Member

@doistbot doistbot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR updates the pre-commit hook to use npm exec instead of npx when running lint-staged, which is a great step toward securing our tooling against potential supply-chain attacks. However, since modern npm versions still fetch missing packages with npm exec, an explicit --no flag is needed to fully enforce using only the locally installed version.

Share FeedbackReview Logs

@@ -1 +1 @@
npx lint-staged
npm exec lint-staged
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] npm exec without --no still fetches missing packages

The PR description states that switching to npm exec ensures only the locally installed version is run. However, in modern npm (v7+), npm exec and npx share the same underlying behavior: if the package is missing locally, both will attempt to fetch it or prompt the user to install it.

To effectively close this supply-chain attack vector and strictly enforce using only the local installation, you must explicitly pass the --no flag to disable fetching. You can use either npm exec --no -- lint-staged or npx --no lint-staged.

Suggested change
npm exec lint-staged
npm exec --no -- lint-staged

@frankieyan frankieyan merged commit 09d513e into main Apr 4, 2026
2 of 3 checks passed
@frankieyan frankieyan deleted the frankie/remove-npx branch April 4, 2026 09:17
frankieyan added a commit that referenced this pull request Apr 4, 2026
#79 replaced npx with npm exec, but npm exec without --no still allows
fetching uninstalled packages from the registry. The --no flag ensures
only locally installed packages can run.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
frankieyan added a commit that referenced this pull request Apr 4, 2026
#79 replaced npx with npm exec, but npm exec without --no still allows
fetching uninstalled packages from the registry. The --no flag ensures
only locally installed packages can run.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

👀 Show PR PR must be reviewed before or after merging

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants