diff --git a/rules/src/generic/npx-usage/npx-usage-json.yml b/rules/src/generic/npx-usage/npx-usage-json.yml new file mode 100644 index 0000000..0a90ecf --- /dev/null +++ b/rules/src/generic/npx-usage/npx-usage-json.yml @@ -0,0 +1,46 @@ +rules: + - id: npx-usage-json + languages: + - json + severity: WARNING + metadata: + tags: [security] + shortDescription: "npx usage introduces supply chain security risks" + confidence: HIGH + help: | + Using npx to install and run packages introduces significant supply chain security risks for the following reasons: + + 1. **Unpinned by default**: Running `npx ` fetches the latest release outside of your lockfile. If a malicious version of a package is published ([example])(https://socket.dev/blog/npm-author-qix-compromised-in-major-supply-chain-attack), `npx` will install and execute it the next time it is run. + + 2. **Bypasses lockfile guarantees**: Packages executed with npx are not added to your project's package.json or lockfile. As a result, their versions and lockfile integrity hashes are not captured for reproducibility, making builds non-deterministic and harder to audit + + ### Recommended practice + - Add packages as dependencies or devDependencies in `package.json`. + - Use your package manager to install and execute them (e.g., `yarn add --dev` followed by `yarn `). + + **Bad example (using npx):** + ```json + { + "scripts": { + "lint": "npx eslint src/" + } + } + ``` + + **Good example (proper dependency):** + ```json + { + "scripts": { + "lint": "eslint src/" + }, + "devDependencies": { + "eslint": "^8.0.0" + } + } + ``` + + message: >- + Avoid using 'npx' to run packages due to supply chain security risks. Instead, install the package + as a dependency / devDependency and invoke it using your package manager to ensure version pinning + and reproducibility. + pattern-regex: '"[^"]*":\s*"(\s*npx\s|npx\s)[^"]*"' \ No newline at end of file diff --git a/rules/src/generic/npx-usage/npx-usage-shell.yml b/rules/src/generic/npx-usage/npx-usage-shell.yml new file mode 100644 index 0000000..8d59213 --- /dev/null +++ b/rules/src/generic/npx-usage/npx-usage-shell.yml @@ -0,0 +1,28 @@ +rules: + - id: npx-usage-shell + languages: + - sh + - dockerfile + severity: WARNING + metadata: + tags: [security] + shortDescription: "npx usage introduces supply chain security risks" + confidence: HIGH + help: | + Using npx to install and run packages introduces significant supply chain security risks for the following reasons: + + 1. **Unpinned by default**: Running `npx ` fetches the latest release outside of your lockfile. If a malicious version of a package is published ([example])(https://socket.dev/blog/npm-author-qix-compromised-in-major-supply-chain-attack), `npx` will install and execute it the next time it is run. + + 2. **Bypasses lockfile guarantees**: Packages executed with npx are not added to your project's package.json or lockfile. As a result, their versions and lockfile integrity hashes are not captured for reproducibility, making builds non-deterministic and harder to audit + + + ### Recommended practice + - Add packages as dependencies or devDependencies in `package.json`. + - Use your package manager to install and execute them (e.g., `yarn add --dev` followed by `yarn `). + + message: >- + Avoid using 'npx' to run packages due to supply chain security risks. Instead, install the package + as a dependency / devDependency and invoke it using your package manager to ensure version pinning + and reproducibility. + patterns: + - pattern: npx ... diff --git a/rules/test/generic/npx-usage/npx-usage-json.test.json b/rules/test/generic/npx-usage/npx-usage-json.test.json new file mode 100644 index 0000000..155aef0 --- /dev/null +++ b/rules/test/generic/npx-usage/npx-usage-json.test.json @@ -0,0 +1,35 @@ +{ + "name": "test-package", + "version": "1.0.0", + "scripts": { + // ruleid: npx-usage-json + "lint": "npx eslint .", + // ruleid: npx-usage-json + "format": "npx prettier --write .", + // ruleid: npx-usage-json + "type-check": "npx tsc --noEmit", + // ruleid: npx-usage-json + "storybook": "npx storybook dev -p 6006", + // ok: npx-usage-json + "test": "yarn jest", + // ok: npx-usage-json + "build": "yarn build", + // ok: npx-usage-json + "start": "yarn start", + // ok: npx-usage-json + "npxify": "yarn npxify", + // ok: npx-usage-json + "setup": "some-npx-tool --config", + // ok: npx-usage-json + "install-npx": "yarn add global-npx" + }, + "devDependencies": { + "eslint": "^8.0.0", + "prettier": "^2.8.0" + }, + "config": { + // ruleid: npx-usage-json + "setupCommand": "npx setup-tool" + }, + "description": "A test package with npx in description - should not be flagged" +} diff --git a/rules/test/generic/npx-usage/npx-usage-shell.test.dockerfile b/rules/test/generic/npx-usage/npx-usage-shell.test.dockerfile new file mode 100644 index 0000000..b6627e3 --- /dev/null +++ b/rules/test/generic/npx-usage/npx-usage-shell.test.dockerfile @@ -0,0 +1,34 @@ +FROM node:18 + +WORKDIR /app + +COPY package.json yarn.lock ./ + +# Test npx usage in Dockerfile - should be flagged +# ruleid: npx-usage-shell +RUN npx create-react-app /tmp/test-app + +# ruleid: npx-usage-shell +RUN npx --yes @storybook/cli init + +# ruleid: npx-usage-shell +RUN npx prettier@2.8.0 --write . + +# Test good alternatives - should not be flagged +# ok: npx-usage-shell +RUN yarn install + +# ok: npx-usage-shell +RUN yarn build + +# ok: npx-usage-shell +RUN yarn dlx create-react-app /tmp/test-app + +COPY . . + +# ok: npx-usage-shell +RUN yarn test + +EXPOSE 3000 + +CMD ["yarn", "start"] diff --git a/rules/test/generic/npx-usage/npx-usage-shell.test.sh b/rules/test/generic/npx-usage/npx-usage-shell.test.sh new file mode 100644 index 0000000..c775614 --- /dev/null +++ b/rules/test/generic/npx-usage/npx-usage-shell.test.sh @@ -0,0 +1,36 @@ +#!/bin/bash + +# Test direct npx usage - should be flagged +# ruleid: npx-usage-shell +npx eslint src/ + +# ruleid: npx-usage-shell +echo "hello world" && npx eslint src/ + +# ruleid: npx-usage-shell +npx create-react-app my-app + +# ruleid: npx-usage-shell +npx @typescript-eslint/parser + +# ruleid: npx-usage-shell +npx prettier@2.8.0 --write . + +# ruleid: npx-usage-shell +npx --yes create-next-app + +# Test good alternatives - should not be flagged +# ok: npx-usage-shell +yarn eslint src/ + +# ok: npx-usage-shell +yarn dlx create-react-app my-app + +# ok: npx-usage-shell +npm run build + +# ok: npx-usage-shell +yarn create next-app + +# ok: npx-usage-shell +yarn prettier --write .