Skip to content

Commit f3d0900

Browse files
frankieyanclaude
andauthored
fix(security): replace npx with npm exec to prevent unintended remote package execution (#106)
* fix(security): replace npx with npm exec to prevent unintended remote package execution npx silently downloads and runs packages from the registry if they aren't installed locally, which is a supply chain security risk. npm exec only runs already-installed packages. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(security): add --no flag to prevent remote package downloads npm exec without --no still allows fetching uninstalled packages from the registry, just like npx. The --no flag ensures only locally installed packages can be executed. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 5ee26bc commit f3d0900

File tree

3 files changed

+10
-10
lines changed

3 files changed

+10
-10
lines changed

.husky/pre-commit

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
npx lint-staged
1+
npm exec --no -- lint-staged

README.md

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -69,15 +69,15 @@ If your source files are in a different location (e.g., `app/` instead of `src/`
6969
Regenerates the entire records file by scanning all source files matching `sourceGlob`. Useful for initialization or picking up changes from skipped Git hooks.
7070

7171
```bash
72-
npx @doist/react-compiler-tracker --overwrite
72+
npm exec --no -- @doist/react-compiler-tracker --overwrite
7373
```
7474

7575
### `--stage-record-file <file1> <file2> ...`
7676

7777
Checks the provided files and updates the records. Exits with code 1 if errors increase (preventing the commit), otherwise updates the records file for the checked files. Reports when errors decrease, celebrating your progress. Deleted files are automatically removed from the records (no need to pass their paths).
7878

7979
```bash
80-
npx @doist/react-compiler-tracker --stage-record-file src/components/Button.tsx src/hooks/useData.ts
80+
npm exec --no -- @doist/react-compiler-tracker --stage-record-file src/components/Button.tsx src/hooks/useData.ts
8181
```
8282

8383
If no files are provided, exits cleanly with a success message.
@@ -87,23 +87,23 @@ If no files are provided, exits cleanly with a success message.
8787
Checks specific files without updating records. Exits with code 1 if checked files show increased error counts (or new errors), or if any provided file does not exist. Reports when errors decrease, celebrating your progress. Primarily for CI to ensure PRs don't introduce new compiler errors.
8888

8989
```bash
90-
npx @doist/react-compiler-tracker --check-files src/components/Button.tsx src/hooks/useData.ts
90+
npm exec --no -- @doist/react-compiler-tracker --check-files src/components/Button.tsx src/hooks/useData.ts
9191
```
9292

9393
### No flags
9494

9595
Checks all source files matching `sourceGlob` and reports the total error count. The records file is **not** updated in this mode.
9696

9797
```bash
98-
npx @doist/react-compiler-tracker
98+
npm exec --no -- @doist/react-compiler-tracker
9999
```
100100

101101
### `--show-errors`
102102

103103
Shows error information from the compiler including file path, line number, and error reason. Can be combined with any command. Errors are displayed for all checked files regardless of whether they increased.
104104

105105
```bash
106-
npx @doist/react-compiler-tracker --check-files --show-errors src/components/Button.tsx
106+
npm exec --no -- @doist/react-compiler-tracker --check-files --show-errors src/components/Button.tsx
107107
```
108108

109109
Example output when errors have increased:
@@ -133,7 +133,7 @@ In `package.json`:
133133
```json
134134
{
135135
"lint-staged": {
136-
"*.{js,jsx,ts,tsx}": "npx @doist/react-compiler-tracker --stage-record-file"
136+
"*.{js,jsx,ts,tsx}": "npm exec --no -- @doist/react-compiler-tracker --stage-record-file"
137137
}
138138
}
139139
```
@@ -148,7 +148,7 @@ With lint-staged, the matched files are automatically passed as arguments to the
148148
# Get changed files in the PR
149149
FILES=$(git diff --name-only origin/main...HEAD -- '*.tsx' '*.ts' '*.jsx' '*.js' | tr '\n' ' ')
150150
if [ -n "$FILES" ]; then
151-
npx @doist/react-compiler-tracker --check-files $FILES
151+
npm exec --no -- @doist/react-compiler-tracker --check-files $FILES
152152
fi
153153
```
154154
@@ -160,7 +160,7 @@ With lint-staged, the matched files are automatically passed as arguments to the
160160
# (deleted files are auto-detected from records, no need to pass them)
161161
FILES=$(git diff --diff-filter=ACMR --cached --name-only -- '*.tsx' '*.ts' '*.jsx' '*.js' | tr '\n' ' ')
162162
if [ -n "$FILES" ]; then
163-
npx @doist/react-compiler-tracker --stage-record-file $FILES
163+
npm exec --no -- @doist/react-compiler-tracker --stage-record-file $FILES
164164
fi
165165
```
166166

src/index.integration.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ const configPath = join(fixtureDir, '.react-compiler-tracker.config.json')
1212
function runCLI(args: string[] = [], cwd = fixtureDir): string {
1313
const cliPath = join(__dirname, 'index.ts')
1414
try {
15-
return execSync(`npx tsx ${cliPath} ${args.join(' ')} 2>&1`, {
15+
return execSync(`npm exec --no -- tsx ${cliPath} ${args.join(' ')} 2>&1`, {
1616
cwd,
1717
encoding: 'utf8',
1818
stdio: ['pipe', 'pipe', 'pipe'],

0 commit comments

Comments
 (0)