@noctcore/eslint-plugin-security
Injection, path traversal, SSRF, open redirect, unsanitized HTML and timing-unsafe comparison: high-precision syntactic sinks only.
What it solves
Section titled “What it solves”A small set of sinks where a user-controlled string becomes a vulnerability: a shell command built by interpolation, a fetch URL whose host comes from a request, a redirect to an arbitrary origin, a path joined from req.params, HTML handed to dangerouslySetInnerHTML unsanitized, an HMAC signature compared with ===, a 'use server' action exported without its action client.
What it will yell at you about
Section titled “What it will yell at you about”It will yell at you rarely, and on purpose: precision is the point. Each rule matches a narrow syntactic shape and stays silent when it cannot prove the value is dynamic, so it will miss taint that flows through a helper. Treat it as a tripwire, not a security audit, and keep a real SAST tool. Three rules are exported but left out of the preset: require-path-containment because it has a high false-positive rate, require-sanitized-html because a real codebase has trusted HTML only you can list, and server-action-through-client because it needs your action-client names. It is a bad fit if you want broad taint tracking; this plugin trades recall for reports you can trust.
Install and configure
Section titled “Install and configure”npm install --save-dev @noctcore/eslint-plugin-security @typescript-eslint/parser# or: bun add -D / pnpm add -D @noctcore/eslint-plugin-security @typescript-eslint/parser// eslint.config.jsimport tsParser from '@typescript-eslint/parser';import security from '@noctcore/eslint-plugin-security';
export default [ { ...security.configs.recommended, files: ['**/*.{ts,tsx}'], languageOptions: { parser: tsParser }, },];
// Rules outside the preset are enabled one by one, e.g.// { rules: { 'noctcore-security/require-path-containment': 'error' } }The recommended preset enables 4 of 7 rules.
Each rule links to its page, with the options it takes and Incorrect and Correct examples. A good first
read is no-shell-interpolation.
| Rule | What it reports | Preset | Fix | Types |
|---|---|---|---|---|
no-shell-interpolation | A dynamically-interpolated command string must not flow into a shell runner (exec/execSync, or spawn/execFile with shell: true). Pass the program and arguments separately. | error | ||
no-timing-unsafe-compare | An HMAC digest or signature must not be compared with === / !== / == / != or Buffer#equals; use crypto.timingSafeEqual. | error | ||
no-user-controlled-fetch-url | Disallow HTTP requests whose origin is not fixed at authoring time: a runtime-controlled host enables SSRF. | error | ||
no-user-controlled-redirect | Disallow redirects whose target origin is not fixed at authoring time: a user-controlled target is an open redirect. | error | ||
require-path-containment | Request-shaped input (req.*) passed directly into path.join / path.resolve without a containment guard is a path-traversal sink. | not listed | ||
require-sanitized-html | HTML reaching dangerouslySetInnerHTML, innerHTML, outerHTML or insertAdjacentHTML must be static markup or pass through a configured sanitizer. | not listed | ||
server-action-through-client | In a 'use server' module every exported action must be built from a configured action client; a raw exported function bypasses input validation, error shaping and middleware. | not listed |
Preset: severity in configs.recommended; off means the preset registers the rule switched off, not listed means it leaves the rule out; both are opt-in, so you turn the rule on yourself. Fix: whether the rule ships an autofix or an editor suggestion. Types: whether the rule needs a type-checked program (parserOptions.projectService).