eslint-plugin-security 3.0.1 → 4.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,3 +1,5 @@
1
+ 'use strict';
2
+
1
3
  const { format } = require('prettier');
2
4
  const prettierRC = require('./.prettierrc.json');
3
5
 
@@ -30,7 +30,7 @@ jobs:
30
30
  strategy:
31
31
  matrix:
32
32
  os: [ubuntu-latest]
33
- node: [18.18.0, 18.x, 20.x, 21.x]
33
+ node: [18.18.0, 18.x, 20.x, 22.x, 24.x]
34
34
  include:
35
35
  - os: windows-latest
36
36
  node: lts/*
@@ -8,10 +8,10 @@ jobs:
8
8
  permissions:
9
9
  contents: read
10
10
  steps:
11
- - uses: actions/checkout@v3
11
+ - uses: actions/checkout@v4
12
12
  with:
13
13
  persist-credentials: false
14
- - uses: actions/setup-node@v3
14
+ - uses: actions/setup-node@v4
15
15
  - uses: beemojs/conventional-pr-action@v3
16
16
  env:
17
17
  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -2,38 +2,46 @@ on:
2
2
  push:
3
3
  branches:
4
4
  - main
5
+
5
6
  name: release-please
7
+
6
8
  jobs:
7
9
  release-please:
8
10
  runs-on: ubuntu-latest
11
+ permissions:
12
+ contents: write
13
+ pull-requests: write
14
+ id-token: write
15
+ models: read
9
16
  steps:
10
- - uses: GoogleCloudPlatform/release-please-action@v2
17
+ - uses: googleapis/release-please-action@16a9c90856f42705d54a6fda1823352bdc62cf38 # v4
11
18
  id: release
12
- with:
13
- release-type: node
14
- package-name: test-release-please
15
- # The logic below handles the npm publication:
16
- - uses: actions/checkout@v3
17
- # these if statements ensure that a publication only occurs when
18
- # a new release is created:
19
+
20
+ - uses: actions/checkout@v6
19
21
  if: ${{ steps.release.outputs.release_created }}
20
- - uses: actions/setup-node@v3
22
+
23
+ - uses: actions/setup-node@v6
21
24
  with:
22
- node-version: 16
23
- registry-url: 'https://registry.npmjs.org'
25
+ node-version: lts/*
26
+ registry-url: https://registry.npmjs.org
24
27
  if: ${{ steps.release.outputs.release_created }}
25
- - run: npm ci
28
+
29
+ # npm 11.5.1 or later is required so update to latest to be sure
30
+ - name: Update npm
31
+ run: npm install -g npm@latest
26
32
  if: ${{ steps.release.outputs.release_created }}
27
- - run: npm publish
28
- env:
29
- NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
33
+
34
+ - name: Publish to npm
35
+ run: |
36
+ npm install
37
+ npm publish --access public
30
38
  if: ${{ steps.release.outputs.release_created }}
31
39
 
32
40
  # Tweets out release announcement
33
- - run: 'npx @humanwhocodes/tweet "${{ github.event.repository.full_name }} v${{ steps.release.outputs.major }}.${{ steps.release.outputs.minor }}.${{ steps.release.outputs.patch }} has been released!\n\n${{ github.event.repository.html_url }}/releases/tag/v${{ steps.release.outputs.major }}.${{ steps.release.outputs.minor }}.${{ steps.release.outputs.patch }}"'
34
- if: ${{ steps.release.outputs.release_created }}
41
+ - run: 'npx @humanwhocodes/tweet "${{ github.event.repository.full_name }} v${{ needs.release-please.outputs.major }}.${{ needs.release-please.outputs.minor }}.${{ needs.release-please.outputs.patch }} has been released!\n\n${{ github.event.repository.html_url }}/releases/tag/v${{ needs.release-please.outputs.major }}.${{ needs.release-please.outputs.minor }}.${{ needs.release-please.outputs.patch }}"'
35
42
  env:
36
43
  TWITTER_CONSUMER_KEY: ${{ secrets.TWITTER_CONSUMER_KEY }}
37
44
  TWITTER_CONSUMER_SECRET: ${{ secrets.TWITTER_CONSUMER_SECRET }}
38
45
  TWITTER_ACCESS_TOKEN_KEY: ${{ secrets.TWITTER_ACCESS_TOKEN_KEY }}
39
46
  TWITTER_ACCESS_TOKEN_SECRET: ${{ secrets.TWITTER_ACCESS_TOKEN_SECRET }}
47
+ if: ${{ steps.release.outputs.release_created }}
@@ -0,0 +1,3 @@
1
+ {
2
+ ".": "4.0.1"
3
+ }
package/CHANGELOG.md CHANGED
@@ -1,5 +1,55 @@
1
1
  # Changelog
2
2
 
3
+ ## [4.0.1](https://github.com/eslint-community/eslint-plugin-security/compare/eslint-plugin-security-v4.0.0...eslint-plugin-security-v4.0.1) (2026-06-12)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * treat import.meta.dirname and import.meta.filename as static ([#200](https://github.com/eslint-community/eslint-plugin-security/issues/200)) ([74c97bb](https://github.com/eslint-community/eslint-plugin-security/commit/74c97bb3326a6b4fe4718b2638bb3b0492cb90fd))
9
+
10
+ ## [4.0.0](https://github.com/eslint-community/eslint-plugin-security/compare/eslint-plugin-security-v3.0.1...eslint-plugin-security-v4.0.0) (2026-02-19)
11
+
12
+
13
+ ### ⚠ BREAKING CHANGES
14
+
15
+ * requires node ^18.18.0 || ^20.9.0 || >=21.1.0 ([#146](https://github.com/eslint-community/eslint-plugin-security/issues/146))
16
+ * switch the recommended config to flat ([#118](https://github.com/eslint-community/eslint-plugin-security/issues/118))
17
+
18
+ ### Features
19
+
20
+ * add config recommended-legacy ([#132](https://github.com/eslint-community/eslint-plugin-security/issues/132)) ([13d3f2f](https://github.com/eslint-community/eslint-plugin-security/commit/13d3f2fc6ba327c894959db30462f3fda0272f0c))
21
+ * Add meta object documentation for all rules ([#79](https://github.com/eslint-community/eslint-plugin-security/issues/79)) ([fb1d9ef](https://github.com/eslint-community/eslint-plugin-security/commit/fb1d9ef56e0cf2705b9e413b483261df394c45e1))
22
+ * detect-bidi-characters rule ([#95](https://github.com/eslint-community/eslint-plugin-security/issues/95)) ([4294d29](https://github.com/eslint-community/eslint-plugin-security/commit/4294d29cca8af5c627de759919add6dd698644ba))
23
+ * **detect-non-literal-fs-filename:** change to track non-top-level `require()` as well ([#105](https://github.com/eslint-community/eslint-plugin-security/issues/105)) ([d3b1543](https://github.com/eslint-community/eslint-plugin-security/commit/d3b15435b45b9ac2ee5f0d3249f590e32369d7d2))
24
+ * extend detect non literal fs filename ([#92](https://github.com/eslint-community/eslint-plugin-security/issues/92)) ([08ba476](https://github.com/eslint-community/eslint-plugin-security/commit/08ba4764a83761f6f44cb28940923f1d25f88581))
25
+ * improve detect-child-process rule ([#108](https://github.com/eslint-community/eslint-plugin-security/issues/108)) ([64ae529](https://github.com/eslint-community/eslint-plugin-security/commit/64ae52944a86f9d9daee769acd63ebbdfc5b6631))
26
+ * **non-literal-require:** support template literals ([#81](https://github.com/eslint-community/eslint-plugin-security/issues/81)) ([208019b](https://github.com/eslint-community/eslint-plugin-security/commit/208019bad4f70a142ab1f0ea7238c37cb70d1a5a))
27
+ * requires node ^18.18.0 || ^20.9.0 || >=21.1.0 ([#146](https://github.com/eslint-community/eslint-plugin-security/issues/146)) ([df1b606](https://github.com/eslint-community/eslint-plugin-security/commit/df1b6063c1224e1163dfdc37c96b64bb52d816bb))
28
+ * switch the recommended config to flat ([#118](https://github.com/eslint-community/eslint-plugin-security/issues/118)) ([e20a366](https://github.com/eslint-community/eslint-plugin-security/commit/e20a3664c2f638466286ae9a97515722fc98f97c))
29
+
30
+
31
+ ### Bug Fixes
32
+
33
+ * Add ESLint 10 compatibility for context.sourceCode API change ([#186](https://github.com/eslint-community/eslint-plugin-security/issues/186)) ([7f9ee77](https://github.com/eslint-community/eslint-plugin-security/commit/7f9ee77677744f7029c545d714d57f0966b3387e))
34
+ * add name to recommended flat config ([#161](https://github.com/eslint-community/eslint-plugin-security/issues/161)) ([aa1c8c5](https://github.com/eslint-community/eslint-plugin-security/commit/aa1c8c57a2df4ce64a202808c5642a41b47d4519))
35
+ * Avoid crash when exec() is passed no arguments ([7f97815](https://github.com/eslint-community/eslint-plugin-security/commit/7f97815accf6bcd87de73c32a967946b1b3b0530)), closes [#82](https://github.com/eslint-community/eslint-plugin-security/issues/82) [#23](https://github.com/eslint-community/eslint-plugin-security/issues/23)
36
+ * Avoid TypeError when exec stub is used with no arguments ([#97](https://github.com/eslint-community/eslint-plugin-security/issues/97)) ([9c18f16](https://github.com/eslint-community/eslint-plugin-security/commit/9c18f16187719b58cc5dfde9860344bad823db28))
37
+ * **detect-child-process:** false positive for destructuring with `exec` ([#102](https://github.com/eslint-community/eslint-plugin-security/issues/102)) ([657921a](https://github.com/eslint-community/eslint-plugin-security/commit/657921a93f6f73c0de6113e497b22e7cf079f520))
38
+ * **detect-child-process:** false positives for destructuring `spawn` ([#103](https://github.com/eslint-community/eslint-plugin-security/issues/103)) ([fdfe37d](https://github.com/eslint-community/eslint-plugin-security/commit/fdfe37d667367e5fd228c26573a1791c81a044d2))
39
+ * Ensure empty eval() doesn't crash detect-eval-with-expression ([#139](https://github.com/eslint-community/eslint-plugin-security/issues/139)) ([8a7c7db](https://github.com/eslint-community/eslint-plugin-security/commit/8a7c7db1e2b49e2831d510b8dc1db235dee0edf0))
40
+ * Ensure everything works with ESLint v9 ([#145](https://github.com/eslint-community/eslint-plugin-security/issues/145)) ([ac50ab4](https://github.com/eslint-community/eslint-plugin-security/commit/ac50ab481ed63d7262513186136ca1429d3b8290))
41
+ * false positives for static expressions in detect-non-literal-fs-filename, detect-child-process, detect-non-literal-regexp, and detect-non-literal-require ([#109](https://github.com/eslint-community/eslint-plugin-security/issues/109)) ([56102b5](https://github.com/eslint-community/eslint-plugin-security/commit/56102b50aed4bd632dd668770eb37de58788110b))
42
+ * generate provenance statement for release ([#168](https://github.com/eslint-community/eslint-plugin-security/issues/168)) ([eb3ee9c](https://github.com/eslint-community/eslint-plugin-security/commit/eb3ee9c38cfd51e13c7a4061f5794db7347c90e5))
43
+ * Incorrect method name in detect-buffer-noassert. ([313c0c6](https://github.com/eslint-community/eslint-plugin-security/commit/313c0c693f48aa85d0c9b65a46f6c620cd10f907)), closes [#63](https://github.com/eslint-community/eslint-plugin-security/issues/63) [#80](https://github.com/eslint-community/eslint-plugin-security/issues/80)
44
+ * release-please config ([#189](https://github.com/eslint-community/eslint-plugin-security/issues/189)) ([2443d10](https://github.com/eslint-community/eslint-plugin-security/commit/2443d10c428724757fac230384ff0692bbd50485))
45
+
46
+ ### [3.0.1](https://www.github.com/eslint-community/eslint-plugin-security/compare/v3.0.0...v3.0.1) (2024-06-14)
47
+
48
+
49
+ ### Bug Fixes
50
+
51
+ * add name to recommended flat config ([#161](https://www.github.com/eslint-community/eslint-plugin-security/issues/161)) ([aa1c8c5](https://www.github.com/eslint-community/eslint-plugin-security/commit/aa1c8c57a2df4ce64a202808c5642a41b47d4519))
52
+
3
53
  ### [3.0.1](https://www.github.com/eslint-community/eslint-plugin-security/compare/v3.0.0...v3.0.1) (2024-06-13)
4
54
 
5
55
 
package/package.json CHANGED
@@ -1,8 +1,9 @@
1
1
  {
2
2
  "name": "eslint-plugin-security",
3
- "version": "3.0.1",
3
+ "version": "4.0.1",
4
4
  "description": "Security rules for eslint",
5
5
  "main": "index.js",
6
+ "type": "commonjs",
6
7
  "scripts": {
7
8
  "changelog": "changelog eslint-plugin-security all > CHANGELOG.md",
8
9
  "cont-int": "npm test && npm run lint",
@@ -55,7 +56,7 @@
55
56
  "eslint-plugin-eslint-plugin": "^5.5.1",
56
57
  "lint-staged": "^12.3.7",
57
58
  "markdownlint-cli": "^0.32.2",
58
- "mocha": "^9.2.2",
59
+ "mocha": "^11.7.5",
59
60
  "npm-run-all": "^4.1.5",
60
61
  "prettier": "^2.6.2",
61
62
  "semantic-release": "^19.0.2",
@@ -0,0 +1,9 @@
1
+ {
2
+ "bump-minor-pre-major": true,
3
+ "packages": {
4
+ ".": {
5
+ "release-type": "node",
6
+ "pull-request-title-pattern": "chore: release ${version} 🚀"
7
+ }
8
+ }
9
+ }
@@ -20,11 +20,12 @@ module.exports = {
20
20
  },
21
21
  },
22
22
  create(context) {
23
+ const sourceCode = context.sourceCode || context.getSourceCode();
23
24
  let csrf = false;
24
25
 
25
26
  return {
26
27
  CallExpression: function (node) {
27
- const token = context.getSourceCode().getTokens(node)[0];
28
+ const token = sourceCode.getTokens(node)[0];
28
29
  const nodeValue = token.value;
29
30
 
30
31
  if (nodeValue === 'express') {
@@ -26,9 +26,10 @@ module.exports = {
26
26
  },
27
27
  },
28
28
  create(context) {
29
+ const sourceCode = context.sourceCode || context.getSourceCode();
29
30
  return {
30
31
  Literal: function (node) {
31
- const token = context.getSourceCode().getTokens(node)[0];
32
+ const token = sourceCode.getTokens(node)[0];
32
33
  const nodeType = token.type;
33
34
  const nodeValue = token.value;
34
35
 
@@ -62,6 +62,13 @@ tester.run(ruleName, require(`../../rules/${ruleName}`), {
62
62
  import url from 'url';
63
63
  const dirname = path.dirname(url.fileURLToPath(import.meta.url));
64
64
  const html = fs.readFileSync(path.resolve(dirname, './index.html'), 'utf-8');`,
65
+ `
66
+ import fs from 'fs';
67
+ import path from 'path';
68
+ const html = fs.readFileSync(path.resolve(import.meta.dirname, './index.html'), 'utf-8');`,
69
+ `
70
+ import fs from 'fs';
71
+ const pkg = fs.readFileSync(import.meta.filename, 'utf-8');`,
65
72
  {
66
73
  code: `
67
74
  import fs from 'fs';
@@ -201,5 +208,12 @@ tester.run(ruleName, require(`../../rules/${ruleName}`), {
201
208
  },
202
209
  errors: [{ message: 'Found readFileSync from package "fs" with non literal argument at index 0' }],
203
210
  },
211
+ {
212
+ code: `
213
+ import fs from 'fs';
214
+ import path from 'path';
215
+ const key = fs.readFileSync(path.resolve(import.meta[prop], './index.html'));`,
216
+ errors: [{ message: 'Found readFileSync from package "fs" with non literal argument at index 0' }],
217
+ },
204
218
  ],
205
219
  });
@@ -253,6 +253,20 @@ describe('isStaticExpression', () => {
253
253
  `,
254
254
  result: [true, false],
255
255
  },
256
+ {
257
+ code: `
258
+ target(import.meta.dirname);
259
+ target(import.meta.filename);
260
+ `,
261
+ result: [true, true],
262
+ },
263
+ {
264
+ code: `
265
+ target(import.meta[prop]);
266
+ target(import.meta.resolve('static'));
267
+ `,
268
+ result: [false, false],
269
+ },
256
270
  ]) {
257
271
  it(code, () => {
258
272
  deepStrictEqual(getIsStaticExpressionResult(code), result);
@@ -7,6 +7,7 @@ const PATH_PACKAGE_NAMES = ['path', 'node:path', 'path/posix', 'node:path/posix'
7
7
  const URL_PACKAGE_NAMES = ['url', 'node:url'];
8
8
  const PATH_CONSTRUCTION_METHOD_NAMES = new Set(['basename', 'dirname', 'extname', 'join', 'normalize', 'relative', 'resolve', 'toNamespacedPath']);
9
9
  const PATH_STATIC_MEMBER_NAMES = new Set(['delimiter', 'sep']);
10
+ const IMPORT_META_STATIC_PROPERTY_NAMES = new Set(['url', 'dirname', 'filename']);
10
11
 
11
12
  /**
12
13
  * @type {WeakMap<import("estree").Expression, boolean>}
@@ -83,7 +84,7 @@ function isStaticExpression({ node, scope }) {
83
84
  return false;
84
85
  }
85
86
  }
86
- return isStaticPath(node) || isStaticFileURLToPath(node) || isStaticImportMetaUrl(node) || isStaticRequireResolve(node) || isStaticCwd(node);
87
+ return isStaticPath(node) || isStaticFileURLToPath(node) || isStaticImportMetaProperty(node) || isStaticRequireResolve(node) || isStaticCwd(node);
87
88
  }
88
89
 
89
90
  /**
@@ -150,17 +151,21 @@ function isStaticExpression({ node, scope }) {
150
151
  }
151
152
 
152
153
  /**
153
- * Checks whether the given expression is an `import.meta.url`.
154
+ * Checks whether the given expression is a static `import.meta` property,
155
+ * i.e. `import.meta.url`, `import.meta.dirname`, or `import.meta.filename`.
156
+ *
157
+ * `import.meta.dirname` and `import.meta.filename` are available in Node.js
158
+ * 20.11.0+ / 21.2.0+ and resolve to constant values for a given module.
154
159
  *
155
160
  * @param {import("estree").Expression} node The node to check.
156
- * @returns {boolean} if true, the given expression is an `import.meta.url`.
161
+ * @returns {boolean} if true, the given expression is a static `import.meta` property.
157
162
  */
158
- function isStaticImportMetaUrl(node) {
163
+ function isStaticImportMetaProperty(node) {
159
164
  return (
160
165
  node.type === 'MemberExpression' &&
161
166
  !node.computed &&
162
167
  node.property.type === 'Identifier' &&
163
- node.property.name === 'url' &&
168
+ IMPORT_META_STATIC_PROPERTY_NAMES.has(node.property.name) &&
164
169
  node.object.type === 'MetaProperty' &&
165
170
  node.object.meta.name === 'import' &&
166
171
  node.object.property.name === 'meta'