eslint-plugin-node-security 4.0.0

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.
Files changed (102) hide show
  1. package/CHANGELOG.md +83 -0
  2. package/README.md +50 -0
  3. package/package.json +79 -0
  4. package/src/index.d.ts +10 -0
  5. package/src/index.js +118 -0
  6. package/src/index.js.map +1 -0
  7. package/src/rules/detect-child-process/index.d.ts +30 -0
  8. package/src/rules/detect-child-process/index.js +535 -0
  9. package/src/rules/detect-child-process/index.js.map +1 -0
  10. package/src/rules/detect-eval-with-expression/index.d.ts +28 -0
  11. package/src/rules/detect-eval-with-expression/index.js +398 -0
  12. package/src/rules/detect-eval-with-expression/index.js.map +1 -0
  13. package/src/rules/detect-non-literal-fs-filename/index.d.ts +26 -0
  14. package/src/rules/detect-non-literal-fs-filename/index.js +460 -0
  15. package/src/rules/detect-non-literal-fs-filename/index.js.map +1 -0
  16. package/src/rules/detect-suspicious-dependencies/index.d.ts +12 -0
  17. package/src/rules/detect-suspicious-dependencies/index.js +77 -0
  18. package/src/rules/detect-suspicious-dependencies/index.js.map +1 -0
  19. package/src/rules/lock-file/index.d.ts +13 -0
  20. package/src/rules/lock-file/index.js +94 -0
  21. package/src/rules/lock-file/index.js.map +1 -0
  22. package/src/rules/no-arbitrary-file-access/index.d.ts +12 -0
  23. package/src/rules/no-arbitrary-file-access/index.js +201 -0
  24. package/src/rules/no-arbitrary-file-access/index.js.map +1 -0
  25. package/src/rules/no-buffer-overread/index.d.ts +39 -0
  26. package/src/rules/no-buffer-overread/index.js +612 -0
  27. package/src/rules/no-buffer-overread/index.js.map +1 -0
  28. package/src/rules/no-cryptojs/index.d.ts +24 -0
  29. package/src/rules/no-cryptojs/index.js +104 -0
  30. package/src/rules/no-cryptojs/index.js.map +1 -0
  31. package/src/rules/no-cryptojs-weak-random/index.d.ts +24 -0
  32. package/src/rules/no-cryptojs-weak-random/index.js +112 -0
  33. package/src/rules/no-cryptojs-weak-random/index.js.map +1 -0
  34. package/src/rules/no-data-in-temp-storage/index.d.ts +14 -0
  35. package/src/rules/no-data-in-temp-storage/index.js +99 -0
  36. package/src/rules/no-data-in-temp-storage/index.js.map +1 -0
  37. package/src/rules/no-deprecated-cipher-method/index.d.ts +23 -0
  38. package/src/rules/no-deprecated-cipher-method/index.js +118 -0
  39. package/src/rules/no-deprecated-cipher-method/index.js.map +1 -0
  40. package/src/rules/no-dynamic-dependency-loading/index.d.ts +12 -0
  41. package/src/rules/no-dynamic-dependency-loading/index.js +55 -0
  42. package/src/rules/no-dynamic-dependency-loading/index.js.map +1 -0
  43. package/src/rules/no-dynamic-require/index.d.ts +21 -0
  44. package/src/rules/no-dynamic-require/index.js +122 -0
  45. package/src/rules/no-dynamic-require/index.js.map +1 -0
  46. package/src/rules/no-ecb-mode/index.d.ts +23 -0
  47. package/src/rules/no-ecb-mode/index.js +113 -0
  48. package/src/rules/no-ecb-mode/index.js.map +1 -0
  49. package/src/rules/no-insecure-key-derivation/index.d.ts +24 -0
  50. package/src/rules/no-insecure-key-derivation/index.js +116 -0
  51. package/src/rules/no-insecure-key-derivation/index.js.map +1 -0
  52. package/src/rules/no-insecure-rsa-padding/index.d.ts +24 -0
  53. package/src/rules/no-insecure-rsa-padding/index.js +110 -0
  54. package/src/rules/no-insecure-rsa-padding/index.js.map +1 -0
  55. package/src/rules/no-pii-in-logs/index.d.ts +12 -0
  56. package/src/rules/no-pii-in-logs/index.js +74 -0
  57. package/src/rules/no-pii-in-logs/index.js.map +1 -0
  58. package/src/rules/no-self-signed-certs/index.d.ts +23 -0
  59. package/src/rules/no-self-signed-certs/index.js +116 -0
  60. package/src/rules/no-self-signed-certs/index.js.map +1 -0
  61. package/src/rules/no-sha1-hash/index.d.ts +24 -0
  62. package/src/rules/no-sha1-hash/index.js +128 -0
  63. package/src/rules/no-sha1-hash/index.js.map +1 -0
  64. package/src/rules/no-static-iv/index.d.ts +23 -0
  65. package/src/rules/no-static-iv/index.js +147 -0
  66. package/src/rules/no-static-iv/index.js.map +1 -0
  67. package/src/rules/no-timing-unsafe-compare/index.d.ts +23 -0
  68. package/src/rules/no-timing-unsafe-compare/index.js +114 -0
  69. package/src/rules/no-timing-unsafe-compare/index.js.map +1 -0
  70. package/src/rules/no-toctou-vulnerability/index.d.ts +26 -0
  71. package/src/rules/no-toctou-vulnerability/index.js +214 -0
  72. package/src/rules/no-toctou-vulnerability/index.js.map +1 -0
  73. package/src/rules/no-unsafe-dynamic-require/index.d.ts +19 -0
  74. package/src/rules/no-unsafe-dynamic-require/index.js +112 -0
  75. package/src/rules/no-unsafe-dynamic-require/index.js.map +1 -0
  76. package/src/rules/no-weak-cipher-algorithm/index.d.ts +25 -0
  77. package/src/rules/no-weak-cipher-algorithm/index.js +190 -0
  78. package/src/rules/no-weak-cipher-algorithm/index.js.map +1 -0
  79. package/src/rules/no-weak-hash-algorithm/index.d.ts +25 -0
  80. package/src/rules/no-weak-hash-algorithm/index.js +218 -0
  81. package/src/rules/no-weak-hash-algorithm/index.js.map +1 -0
  82. package/src/rules/no-zip-slip/index.d.ts +35 -0
  83. package/src/rules/no-zip-slip/index.js +451 -0
  84. package/src/rules/no-zip-slip/index.js.map +1 -0
  85. package/src/rules/prefer-native-crypto/index.d.ts +23 -0
  86. package/src/rules/prefer-native-crypto/index.js +124 -0
  87. package/src/rules/prefer-native-crypto/index.js.map +1 -0
  88. package/src/rules/require-dependency-integrity/index.d.ts +12 -0
  89. package/src/rules/require-dependency-integrity/index.js +70 -0
  90. package/src/rules/require-dependency-integrity/index.js.map +1 -0
  91. package/src/rules/require-secure-credential-storage/index.d.ts +12 -0
  92. package/src/rules/require-secure-credential-storage/index.js +54 -0
  93. package/src/rules/require-secure-credential-storage/index.js.map +1 -0
  94. package/src/rules/require-secure-deletion/index.d.ts +12 -0
  95. package/src/rules/require-secure-deletion/index.js +46 -0
  96. package/src/rules/require-secure-deletion/index.js.map +1 -0
  97. package/src/rules/require-storage-encryption/index.d.ts +12 -0
  98. package/src/rules/require-storage-encryption/index.js +54 -0
  99. package/src/rules/require-storage-encryption/index.js.map +1 -0
  100. package/src/types/index.d.ts +24 -0
  101. package/src/types/index.js +8 -0
  102. package/src/types/index.js.map +1 -0
@@ -0,0 +1,94 @@
1
+ "use strict";
2
+ /**
3
+ * Copyright (c) 2025 Ofri Peretz
4
+ * Licensed under the MIT License. Use of this source code is governed by the
5
+ * MIT license that can be found in the LICENSE file.
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.lockFile = void 0;
9
+ /**
10
+ * @fileoverview Ensure package lock file exists
11
+ * @see https://owasp.org/www-project-mobile-top-10/
12
+ * @see https://cwe.mitre.org/data/definitions/829.html
13
+ */
14
+ const eslint_devkit_1 = require("@interlace/eslint-devkit");
15
+ exports.lockFile = (0, eslint_devkit_1.createRule)({
16
+ name: 'lock-file',
17
+ meta: {
18
+ type: 'suggestion',
19
+ docs: {
20
+ description: 'Ensure package lock file exists for the configured package manager',
21
+ },
22
+ messages: {
23
+ violationDetected: (0, eslint_devkit_1.formatLLMMessage)({
24
+ icon: eslint_devkit_1.MessageIcons.SECURITY,
25
+ issueName: 'Lock File Missing',
26
+ cwe: 'CWE-829',
27
+ description: 'Package lock file missing ({{ lockFile }}) for {{ packageManager }}. Commit the lock file to ensure supply chain integrity.',
28
+ severity: 'HIGH',
29
+ fix: 'Generate and commit the {{ lockFile }} file.',
30
+ documentationLink: 'https://cwe.mitre.org/data/definitions/829.html',
31
+ })
32
+ },
33
+ schema: [
34
+ {
35
+ type: 'object',
36
+ properties: {
37
+ packageManager: {
38
+ type: 'string',
39
+ enum: ['npm', 'yarn', 'pnpm'],
40
+ },
41
+ },
42
+ additionalProperties: false,
43
+ },
44
+ ],
45
+ },
46
+ defaultOptions: [{ packageManager: 'npm' }],
47
+ create(context) {
48
+ const fs = require('node:fs');
49
+ const path = require('node:path');
50
+ // Check once per file
51
+ let checked = false;
52
+ const options = context.options[0] || {};
53
+ const packageManager = options.packageManager || 'npm';
54
+ const lockFiles = {
55
+ npm: 'package-lock.json',
56
+ yarn: 'yarn.lock',
57
+ pnpm: 'pnpm-lock.yaml',
58
+ };
59
+ const targetLockFile = lockFiles[packageManager];
60
+ return {
61
+ Program(node) {
62
+ if (checked)
63
+ return;
64
+ checked = true;
65
+ // Find project root (simplified)
66
+ let dir = path.dirname(context.filename);
67
+ let found = false;
68
+ // Search up to 10 levels for the lock file
69
+ for (let i = 0; i < 10; i++) {
70
+ const lockPath = path.join(dir, targetLockFile);
71
+ if (fs.existsSync(lockPath)) {
72
+ found = true;
73
+ break;
74
+ }
75
+ const parentDir = path.dirname(dir);
76
+ if (parentDir === dir)
77
+ break;
78
+ dir = parentDir;
79
+ }
80
+ if (!found) {
81
+ context.report({
82
+ node,
83
+ messageId: 'violationDetected',
84
+ data: {
85
+ packageManager,
86
+ lockFile: targetLockFile,
87
+ }
88
+ });
89
+ }
90
+ },
91
+ };
92
+ },
93
+ });
94
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../../packages/eslint-plugin-node-security/src/rules/lock-file/index.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;;AAEH;;;;GAIG;AAEH,4DAAsF;AAWzE,QAAA,QAAQ,GAAG,IAAA,0BAAU,EAA0B;IAC1D,IAAI,EAAE,WAAW;IACjB,IAAI,EAAE;QACJ,IAAI,EAAE,YAAY;QAClB,IAAI,EAAE;YACJ,WAAW,EAAE,oEAAoE;SAClF;QACD,QAAQ,EAAE;YACR,iBAAiB,EAAE,IAAA,gCAAgB,EAAC;gBAClC,IAAI,EAAE,4BAAY,CAAC,QAAQ;gBAC3B,SAAS,EAAE,mBAAmB;gBAC9B,GAAG,EAAE,SAAS;gBACd,WAAW,EAAE,6HAA6H;gBAC1I,QAAQ,EAAE,MAAM;gBAChB,GAAG,EAAE,8CAA8C;gBACnD,iBAAiB,EAAE,iDAAiD;aACrE,CAAC;SACH;QACD,MAAM,EAAE;YACN;gBACE,IAAI,EAAE,QAAQ;gBACd,UAAU,EAAE;oBACV,cAAc,EAAE;wBACd,IAAI,EAAE,QAAQ;wBACd,IAAI,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC;qBAC9B;iBACF;gBACD,oBAAoB,EAAE,KAAK;aAC5B;SACF;KACF;IACD,cAAc,EAAE,CAAC,EAAE,cAAc,EAAE,KAAK,EAAE,CAAC;IAC3C,MAAM,CAAC,OAAO;QACZ,MAAM,EAAE,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;QAC9B,MAAM,IAAI,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;QAElC,sBAAsB;QACtB,IAAI,OAAO,GAAG,KAAK,CAAC;QACpB,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QACzC,MAAM,cAAc,GAAG,OAAO,CAAC,cAAc,IAAI,KAAK,CAAC;QAEvD,MAAM,SAAS,GAA2B;YACxC,GAAG,EAAE,mBAAmB;YACxB,IAAI,EAAE,WAAW;YACjB,IAAI,EAAE,gBAAgB;SACvB,CAAC;QAEF,MAAM,cAAc,GAAG,SAAS,CAAC,cAAc,CAAC,CAAC;QAEjD,OAAO;YACL,OAAO,CAAC,IAAsB;gBAC5B,IAAI,OAAO;oBAAE,OAAO;gBACpB,OAAO,GAAG,IAAI,CAAC;gBAEf,iCAAiC;gBACjC,IAAI,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;gBACzC,IAAI,KAAK,GAAG,KAAK,CAAC;gBAElB,2CAA2C;gBAC3C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC;oBAC5B,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC;oBAChD,IAAI,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;wBAC5B,KAAK,GAAG,IAAI,CAAC;wBACb,MAAM;oBACR,CAAC;oBACD,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;oBACpC,IAAI,SAAS,KAAK,GAAG;wBAAE,MAAM;oBAC7B,GAAG,GAAG,SAAS,CAAC;gBAClB,CAAC;gBAED,IAAI,CAAC,KAAK,EAAE,CAAC;oBACX,OAAO,CAAC,MAAM,CAAC;wBACb,IAAI;wBACJ,SAAS,EAAE,mBAAmB;wBAC9B,IAAI,EAAE;4BACJ,cAAc;4BACd,QAAQ,EAAE,cAAc;yBACzB;qBACF,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;SACF,CAAC;IACJ,CAAC;CACF,CAAC,CAAC"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Copyright (c) 2025 Ofri Peretz
3
+ * Licensed under the MIT License. Use of this source code is governed by the
4
+ * MIT license that can be found in the LICENSE file.
5
+ */
6
+ export interface Options {
7
+ }
8
+ type RuleOptions = [Options?];
9
+ export declare const noArbitraryFileAccess: import("@typescript-eslint/utils/ts-eslint").RuleModule<"violationDetected", RuleOptions, unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
10
+ name: string;
11
+ };
12
+ export {};
@@ -0,0 +1,201 @@
1
+ "use strict";
2
+ /**
3
+ * Copyright (c) 2025 Ofri Peretz
4
+ * Licensed under the MIT License. Use of this source code is governed by the
5
+ * MIT license that can be found in the LICENSE file.
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.noArbitraryFileAccess = void 0;
9
+ /**
10
+ * @fileoverview Prevent file access from user input
11
+ *
12
+ * False Positive Reduction:
13
+ * This rule detects safe patterns including:
14
+ * - path.basename() sanitization
15
+ * - path.join() with validated base directories
16
+ * - startsWith() validation guards
17
+ * - Early-return throw patterns
18
+ */
19
+ const eslint_devkit_1 = require("@interlace/eslint-devkit");
20
+ exports.noArbitraryFileAccess = (0, eslint_devkit_1.createRule)({
21
+ name: 'no-arbitrary-file-access',
22
+ meta: {
23
+ type: 'problem',
24
+ docs: {
25
+ description: 'Prevent file access from user input',
26
+ },
27
+ messages: {
28
+ violationDetected: (0, eslint_devkit_1.formatLLMMessage)({
29
+ icon: eslint_devkit_1.MessageIcons.SECURITY,
30
+ issueName: 'Arbitrary File Access',
31
+ cwe: 'CWE-22',
32
+ description: 'File path from user input - path traversal vulnerability',
33
+ severity: 'HIGH',
34
+ fix: 'Validate and sanitize file paths, use allowlists',
35
+ documentationLink: 'https://cwe.mitre.org/data/definitions/22.html',
36
+ })
37
+ },
38
+ schema: [],
39
+ },
40
+ defaultOptions: [],
41
+ create(context) {
42
+ const sourceCode = context.sourceCode;
43
+ function report(node) {
44
+ context.report({ node, messageId: 'violationDetected' });
45
+ }
46
+ const fsReadMethods = ['readFile', 'readFileSync', 'readdir', 'readdirSync', 'stat', 'statSync'];
47
+ const fsWriteMethods = ['writeFile', 'writeFileSync', 'appendFile', 'appendFileSync'];
48
+ const userInputSources = ['req', 'request', 'params', 'query', 'body'];
49
+ // Track variables that have been sanitized with path.basename()
50
+ const sanitizedVariables = new Set();
51
+ // Track variables that have been validated with startsWith() guards
52
+ const validatedVariables = new Set();
53
+ /**
54
+ * Check if a variable is assigned from path.basename() or path.join() with basename
55
+ */
56
+ function checkVariableDeclaration(node) {
57
+ if (node.id.type !== 'Identifier' || !node.init) {
58
+ return;
59
+ }
60
+ const varName = node.id.name;
61
+ const init = node.init;
62
+ // Check for path.basename() assignment
63
+ if (init.type === 'CallExpression' &&
64
+ init.callee.type === 'MemberExpression' &&
65
+ init.callee.object.type === 'Identifier' &&
66
+ init.callee.object.name === 'path' &&
67
+ init.callee.property.type === 'Identifier' &&
68
+ init.callee.property.name === 'basename') {
69
+ sanitizedVariables.add(varName);
70
+ }
71
+ // Check for path.join() with a sanitized variable or literal base
72
+ if (init.type === 'CallExpression' &&
73
+ init.callee.type === 'MemberExpression' &&
74
+ init.callee.object.type === 'Identifier' &&
75
+ init.callee.object.name === 'path' &&
76
+ init.callee.property.type === 'Identifier' &&
77
+ init.callee.property.name === 'join') {
78
+ // Check if any argument is a sanitized variable
79
+ const hasSanitizedArg = init.arguments.some((arg) => arg.type === 'Identifier' && sanitizedVariables.has(arg.name));
80
+ // Check if first arg is a safe base (literal or known safe variable)
81
+ const firstArg = init.arguments[0];
82
+ const hasSafeBase = firstArg && (firstArg.type === 'Literal' ||
83
+ (firstArg.type === 'Identifier' && /^(SAFE|BASE|ROOT|UPLOAD|PUBLIC)/i.test(firstArg.name)));
84
+ if (hasSanitizedArg && hasSafeBase) {
85
+ sanitizedVariables.add(varName);
86
+ }
87
+ }
88
+ }
89
+ /**
90
+ * Check if there's a startsWith() guard validation for this variable
91
+ * Looks for patterns like:
92
+ * if (!path.startsWith(baseDir)) { throw ... }
93
+ * if (!path.startsWith(baseDir)) { return ... }
94
+ */
95
+ function hasStartsWithGuard(node, varName) {
96
+ // Already validated
97
+ if (validatedVariables.has(varName)) {
98
+ return true;
99
+ }
100
+ // Walk up to find the containing block or function
101
+ let current = node.parent;
102
+ while (current) {
103
+ // If we've reached a function body or block, search its statements
104
+ if (current.type === eslint_devkit_1.AST_NODE_TYPES.BlockStatement) {
105
+ const statements = current.body;
106
+ // Look for IF statements in this block that validate our variable
107
+ for (const stmt of statements) {
108
+ if (stmt.type === eslint_devkit_1.AST_NODE_TYPES.IfStatement) {
109
+ const testText = sourceCode.getText(stmt.test).toLowerCase();
110
+ // Check for startsWith() validation pattern with our variable
111
+ if (testText.includes('startswith') && testText.includes(varName.toLowerCase())) {
112
+ // Check if this is a guard clause (negated condition with throw/return)
113
+ const consequent = stmt.consequent;
114
+ // Handle block statement: if (...) { throw/return; }
115
+ if (consequent.type === eslint_devkit_1.AST_NODE_TYPES.BlockStatement && consequent.body.length > 0) {
116
+ const firstStmt = consequent.body[0];
117
+ if (firstStmt.type === eslint_devkit_1.AST_NODE_TYPES.ThrowStatement || firstStmt.type === eslint_devkit_1.AST_NODE_TYPES.ReturnStatement) {
118
+ validatedVariables.add(varName);
119
+ return true;
120
+ }
121
+ }
122
+ // Handle direct statement: if (...) throw/return;
123
+ if (consequent.type === eslint_devkit_1.AST_NODE_TYPES.ThrowStatement || consequent.type === eslint_devkit_1.AST_NODE_TYPES.ReturnStatement) {
124
+ validatedVariables.add(varName);
125
+ return true;
126
+ }
127
+ }
128
+ }
129
+ }
130
+ }
131
+ // Also check if current IS an if statement (when node is inside the consequent)
132
+ if (current.type === eslint_devkit_1.AST_NODE_TYPES.IfStatement) {
133
+ const testText = sourceCode.getText(current.test).toLowerCase();
134
+ if (testText.includes('startswith') && testText.includes(varName.toLowerCase())) {
135
+ validatedVariables.add(varName);
136
+ return true;
137
+ }
138
+ }
139
+ current = current.parent;
140
+ }
141
+ return false;
142
+ }
143
+ /**
144
+ * Check if a variable comes from a sanitized/validated source
145
+ */
146
+ function isVariableSafe(varName, node) {
147
+ // Already tracked as sanitized
148
+ if (sanitizedVariables.has(varName)) {
149
+ return true;
150
+ }
151
+ // Has startsWith guard validation
152
+ if (hasStartsWithGuard(node, varName)) {
153
+ return true;
154
+ }
155
+ // Check naming conventions that suggest safety
156
+ if (/^(safe|sanitized|validated|clean)/i.test(varName)) {
157
+ return true;
158
+ }
159
+ return false;
160
+ }
161
+ return {
162
+ // Track variable declarations for sanitization patterns
163
+ VariableDeclarator(node) {
164
+ checkVariableDeclaration(node);
165
+ },
166
+ CallExpression(node) {
167
+ // Detect fs.* with user input
168
+ if (node.callee.type === 'MemberExpression' &&
169
+ node.callee.object.type === 'Identifier' &&
170
+ node.callee.object.name === 'fs' &&
171
+ node.callee.property.type === 'Identifier' &&
172
+ [...fsReadMethods, ...fsWriteMethods].includes(node.callee.property.name)) {
173
+ const pathArg = node.arguments[0];
174
+ // Skip if path is a literal (safe)
175
+ if (pathArg && pathArg.type === 'Literal') {
176
+ return;
177
+ }
178
+ // Check if path is a variable
179
+ if (pathArg && pathArg.type === 'Identifier') {
180
+ const varName = pathArg.name;
181
+ // Skip if variable is sanitized or validated
182
+ if (isVariableSafe(varName, node)) {
183
+ return;
184
+ }
185
+ report(node);
186
+ return;
187
+ }
188
+ // Flag if path is from a member expression (user input sources)
189
+ if (pathArg?.type === 'MemberExpression' &&
190
+ pathArg.object.type === 'Identifier') {
191
+ const objName = pathArg.object.name.toLowerCase();
192
+ if (userInputSources.includes(objName)) {
193
+ report(node);
194
+ }
195
+ }
196
+ }
197
+ },
198
+ };
199
+ },
200
+ });
201
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../../packages/eslint-plugin-node-security/src/rules/no-arbitrary-file-access/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Copyright (c) 2025 Ofri Peretz
3
+ * Licensed under the MIT License. Use of this source code is governed by the
4
+ * MIT license that can be found in the LICENSE file.
5
+ */
6
+ /**
7
+ * ESLint Rule: no-buffer-overread
8
+ * Detects buffer access beyond bounds (CWE-126)
9
+ *
10
+ * Buffer overread occurs when reading from buffers beyond their allocated
11
+ * length, potentially leading to information disclosure, crashes, or
12
+ * other security issues.
13
+ *
14
+ * False Positive Reduction:
15
+ * This rule uses security utilities to reduce false positives by detecting:
16
+ * - Safe buffer access patterns
17
+ * - Bounds checking operations
18
+ * - JSDoc annotations (@safe, @validated)
19
+ * - Input validation functions
20
+ */
21
+ import type { TSESLint, SecurityRuleOptions } from '@interlace/eslint-devkit';
22
+ type MessageIds = 'bufferOverread' | 'unsafeBufferAccess' | 'missingBoundsCheck' | 'negativeBufferIndex' | 'userControlledBufferIndex' | 'unsafeBufferSlice' | 'bufferLengthNotChecked' | 'useSafeBufferAccess' | 'validateBufferIndices' | 'checkBufferBounds' | 'strategyBoundsChecking' | 'strategyInputValidation' | 'strategySafeBuffers';
23
+ export interface Options extends SecurityRuleOptions {
24
+ /** Buffer methods to check for bounds safety */
25
+ bufferMethods?: string[];
26
+ /** Functions that validate buffer indices */
27
+ boundsCheckFunctions?: string[];
28
+ /** Buffer types to monitor */
29
+ bufferTypes?: string[];
30
+ /** Additional function names to consider as buffer index validators */
31
+ trustedSanitizers?: string[];
32
+ /** Additional JSDoc annotations to consider as safe markers */
33
+ strictMode?: boolean;
34
+ }
35
+ type RuleOptions = [Options?];
36
+ export declare const noBufferOverread: TSESLint.RuleModule<MessageIds, RuleOptions, unknown, TSESLint.RuleListener> & {
37
+ name: string;
38
+ };
39
+ export {};