├── .github └── workflows │ ├── ci.yml │ └── release.yml ├── .gitignore ├── LICENSE ├── README.md ├── docs ├── enforce-https.md ├── no-client-side-secrets.md ├── no-dangerously-set-inner-html.md ├── no-eval.md ├── no-inline-styles.md ├── no-open-redirects.md ├── require-rel-noopener-noreferrer.md └── require-script-integrity.md ├── eslint.config.js ├── jest.config.js ├── package.json ├── pnpm-lock.yaml ├── src ├── index.ts ├── rules │ ├── enforce-https.ts │ ├── no-client-side-secrets.ts │ ├── no-dangerously-set-inner-html.ts │ ├── no-eval.ts │ ├── no-inline-styles.ts │ ├── no-open-redirects.ts │ ├── require-rel-noopener-noreferrer.ts │ └── require-script-integrity.ts └── utils │ ├── next-runtime.ts │ └── rule.ts ├── tests └── rules │ ├── enforce-https.test.ts │ ├── no-client-side-secrets.test.ts │ ├── no-dangerously-set-inner-html.test.ts │ ├── no-eval.test.ts │ ├── no-inline-styles.test.ts │ ├── no-open-redirects.test.ts │ ├── require-rel-noopener-noreferrer.test.ts │ └── require-script-integrity.test.ts └── tsconfig.json /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | # .github/workflows/ci.yml 2 | 3 | name: CI 4 | 5 | on: 6 | push: 7 | branches: 8 | - main 9 | pull_request: 10 | branches: 11 | - main 12 | 13 | jobs: 14 | test: 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - name: Checkout repository 19 | uses: actions/checkout@v3 20 | 21 | - name: Set up Node.js 22 | uses: actions/setup-node@v3 23 | with: 24 | node-version: "18" # or another version if your project requires it 25 | 26 | - name: Install pnpm 27 | run: | 28 | npm install -g pnpm 29 | 30 | - name: Install dependencies 31 | run: | 32 | pnpm install 33 | 34 | - name: Run tests 35 | run: | 36 | pnpm test 37 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | # .github/workflows/release.yml 2 | 3 | name: Release 4 | 5 | on: 6 | push: 7 | tags: 8 | - "v*.*.*" # Trigger on version tags like v1.0.0 9 | 10 | jobs: 11 | publish: 12 | runs-on: ubuntu-latest 13 | if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') 14 | 15 | steps: 16 | - name: Checkout repository 17 | uses: actions/checkout@v3 18 | 19 | - name: Set up Node.js 20 | uses: actions/setup-node@v3 21 | with: 22 | node-version: "18" # Or specify another version if necessary 23 | 24 | - name: Install pnpm 25 | run: | 26 | npm install -g pnpm 27 | 28 | - name: Install dependencies 29 | run: | 30 | pnpm install 31 | 32 | - name: Build the package 33 | run: | 34 | pnpm build # If your package has a build step; adjust as needed 35 | 36 | - name: Publish to npm 37 | env: 38 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} 39 | run: | 40 | pnpm publish --access public --no-git-checks 41 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | coverage/ 3 | tsconfig.tsbuildinfo 4 | node_modules/ -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Simon Koeck 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # @shipsecure/eslint-plugin-next 2 | 3 | ## Overview 4 | 5 | `@shipsecure/eslint-plugin-next` is a custom ESLint plugin designed to enhance the security of Next.js applications by identifying potentially insecure patterns in code. This plugin offers a set of rules specifically tailored to prevent common security pitfalls in Next.js, encouraging best practices and securing your app's frontend and backend code. 6 | 7 | ## Features 8 | 9 | - Rules for Secure Code: Detects usage of unsecure URLs, inline scripts, eval, and other potential security vulnerabilities. 10 | - Recommended Configurations: Provides a recommended set of rules for immediate security improvements. 11 | - Easy to Integrate: Seamlessly integrates with any Next.js project with simple installation and configuration. 12 | 13 | ## Installation 14 | 15 | ```bash 16 | npm install @shipsecure/eslint-plugin-next --save-dev 17 | ``` 18 | 19 | ## Usage 20 | 21 | ### Flat config (requires eslint >= v8.23.0) 22 | 23 | Add the following to your `eslint.config.js` file: 24 | 25 | ```javascript 26 | const shipsecureNext = require("@shipsecure/eslint-plugin-next"); 27 | 28 | module.exports = [shipsecureNext.configs.recommended]; 29 | ``` 30 | 31 | ### eslintrc config (deprecated) 32 | 33 | Add the following to your `.eslintrc` file: 34 | 35 | ```javascript 36 | module.exports = { 37 | extends: ["plugin:@shipsecure/next/recommended-legacy"], 38 | }; 39 | ``` 40 | 41 | ## Contributing 42 | 43 | Contributions are welcome! If you'd like to add new rules, suggest enhancements, or report issues, please open a pull request or issue on our [GitHub repository](https://github.com/shipsecure-labs/eslint-plugin-next). 44 | 45 | ### Steps to Contribute 46 | 47 |
    48 |
  1. Fork the repository.
  2. 49 |
  3. Create a new branch for your feature (git checkout -b feature-name).
  4. 50 |
  5. Make your changes and add tests.
  6. 51 |
  7. Run tests to ensure everything works (npm test).
  8. 52 |
  9. Push your branch and submit a pull request.
  10. 53 |
54 | 55 | ## License 56 | 57 | This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. 58 | -------------------------------------------------------------------------------- /docs/enforce-https.md: -------------------------------------------------------------------------------- 1 | # enforce-https 2 | 3 | ## Rule Details 4 | 5 | This rule enforces the use of HTTPS in network requests. 6 | 7 | ## Examples 8 | 9 | Examples of **incorrect** code for this rule: 10 | 11 | ```js 12 | fetch("http://example.com/api/data"); 13 | axios.post("http://example.com/api/data"); 14 | ``` 15 | 16 | Examples of **correct** code for this rule: 17 | 18 | ```js 19 | fetch("https://example.com/api/data"); 20 | ``` 21 | 22 | ## Further Reading 23 | 24 | - [Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) 25 | -------------------------------------------------------------------------------- /docs/no-client-side-secrets.md: -------------------------------------------------------------------------------- 1 | # no-client-side-secrets 2 | 3 | ## Rule Details 4 | 5 | This rule disables the usage of secrets in combination with NEXT_PUBLIC. 6 | 7 | ## Examples 8 | 9 | Examples of **incorrect** code for this rule: 10 | 11 | ```js 12 | const key = process.env.NEXT_PUBLIC_API_KEY; 13 | ``` 14 | 15 | Examples of **correct** code for this rule: 16 | 17 | ```js 18 | const key = process.env.API_KEY; 19 | ``` 20 | 21 | ## Further Reading 22 | 23 | - [Next.js Configure Environment Variables](https://nextjs.org/docs/pages/building-your-application/configuring/environment-variables) 24 | -------------------------------------------------------------------------------- /docs/no-dangerously-set-inner-html.md: -------------------------------------------------------------------------------- 1 | # no-dangerously-set-inner-html 2 | 3 | ## Rule Details 4 | 5 | This rule disables the usage of dangerouslySetInnerHTML. 6 | 7 | ## Examples 8 | 9 | Examples of **incorrect** code for this rule: 10 | 11 | ```js 12 |
13 | ``` 14 | 15 | Examples of **correct** code for this rule: 16 | 17 | ```js 18 |
Safe Content
19 | ``` 20 | -------------------------------------------------------------------------------- /docs/no-eval.md: -------------------------------------------------------------------------------- 1 | # no-eval 2 | 3 | ## Rule Details 4 | 5 | This rule disables the usage of eval. 6 | 7 | ## Examples 8 | 9 | Examples of **incorrect** code for this rule: 10 | 11 | ```js 12 | eval("return 'foo';"); 13 | ``` 14 | 15 | Examples of **correct** code for this rule: 16 | 17 | ```js 18 | const result = "foo"; 19 | ``` 20 | -------------------------------------------------------------------------------- /docs/no-inline-styles.md: -------------------------------------------------------------------------------- 1 | # no-inline-styles 2 | 3 | ## Rule Details 4 | 5 | This rule disables the usage of inline styles. 6 | 7 | ## Examples 8 | 9 | Examples of **incorrect** code for this rule: 10 | 11 | ```jsx 12 |
13 | ``` 14 | 15 | Examples of **correct** code for this rule: 16 | 17 | ```jsx 18 |
Safe Content
19 | ``` 20 | -------------------------------------------------------------------------------- /docs/no-open-redirects.md: -------------------------------------------------------------------------------- 1 | # no-open-redirects 2 | 3 | ## Rule Details 4 | 5 | This rule disables the usage of user-controlled values in href attributes to prevent open redirects. 6 | 7 | ## Examples 8 | 9 | Examples of **incorrect** code for this rule: 10 | 11 | ```jsx 12 | Test 13 | ``` 14 | 15 | ```jsx 16 | Test 17 | ``` 18 | 19 | Examples of **correct** code for this rule: 20 | 21 | ```jsx 22 | Test 23 | ``` 24 | 25 | ```jsx 26 | Test 27 | ``` 28 | -------------------------------------------------------------------------------- /docs/require-rel-noopener-noreferrer.md: -------------------------------------------------------------------------------- 1 | # require-rel-noopener-noreferrer 2 | 3 | ## Rule Details 4 | 5 | This rule requires the use of rel="noopener noreferrer" on external links to prevent tab-nabbing. 6 | 7 | ## Examples 8 | 9 | Examples of **incorrect** code for this rule: 10 | 11 | ```jsx 12 | Test 13 | ``` 14 | 15 | ```jsx 16 | Test 17 | ``` 18 | 19 | Examples of **correct** code for this rule: 20 | 21 | ```jsx 22 | 23 | Test 24 | 25 | ``` 26 | 27 | ```jsx 28 | 29 | Test 30 | 31 | ``` 32 | -------------------------------------------------------------------------------- /docs/require-script-integrity.md: -------------------------------------------------------------------------------- 1 | # require-script-integrity 2 | 3 | ## Rule Details 4 | 5 | This rule requires the use of integrity attribute on external scripts to prevent CDN tampering. 6 | 7 | ## Examples 8 | 9 | Examples of **incorrect** code for this rule: 10 | 11 | ```jsx 12 |