eslint-plugin-secure-coding 2.3.3 → 2.4.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 (337) hide show
  1. package/CHANGELOG.md +51 -1
  2. package/README.md +2 -2
  3. package/package.json +1 -1
  4. package/src/index.d.ts +32 -0
  5. package/src/index.js +416 -0
  6. package/src/rules/detect-child-process/index.d.ts +11 -0
  7. package/src/rules/detect-child-process/index.js +529 -0
  8. package/src/rules/detect-eval-with-expression/index.d.ts +9 -0
  9. package/src/rules/detect-eval-with-expression/index.js +392 -0
  10. package/src/rules/detect-mixed-content/index.d.ts +8 -0
  11. package/src/rules/detect-mixed-content/index.js +44 -0
  12. package/src/rules/detect-non-literal-fs-filename/index.d.ts +7 -0
  13. package/src/rules/detect-non-literal-fs-filename/index.js +454 -0
  14. package/src/rules/detect-non-literal-regexp/index.d.ts +9 -0
  15. package/src/rules/detect-non-literal-regexp/index.js +403 -0
  16. package/src/rules/detect-object-injection/index.d.ts +11 -0
  17. package/src/rules/detect-object-injection/index.js +560 -0
  18. package/src/rules/detect-suspicious-dependencies/index.d.ts +8 -0
  19. package/src/rules/detect-suspicious-dependencies/index.js +71 -0
  20. package/src/rules/detect-weak-password-validation/index.d.ts +6 -0
  21. package/src/rules/detect-weak-password-validation/index.js +58 -0
  22. package/src/rules/no-allow-arbitrary-loads/index.d.ts +8 -0
  23. package/src/rules/no-allow-arbitrary-loads/index.js +47 -0
  24. package/src/rules/no-arbitrary-file-access/index.d.ts +13 -0
  25. package/src/rules/no-arbitrary-file-access/index.js +195 -0
  26. package/src/rules/no-buffer-overread/index.d.ts +29 -0
  27. package/src/rules/no-buffer-overread/index.js +606 -0
  28. package/src/rules/no-clickjacking/index.d.ts +10 -0
  29. package/src/rules/no-clickjacking/index.js +396 -0
  30. package/src/rules/no-client-side-auth-logic/index.d.ts +6 -0
  31. package/src/rules/no-client-side-auth-logic/index.js +69 -0
  32. package/src/rules/no-credentials-in-query-params/index.d.ts +8 -0
  33. package/src/rules/no-credentials-in-query-params/index.js +57 -0
  34. package/src/rules/no-data-in-temp-storage/index.d.ts +6 -0
  35. package/src/rules/no-data-in-temp-storage/index.js +64 -0
  36. package/src/rules/no-debug-code-in-production/index.d.ts +8 -0
  37. package/src/rules/no-debug-code-in-production/index.js +51 -0
  38. package/src/rules/no-directive-injection/index.d.ts +12 -0
  39. package/src/rules/no-directive-injection/index.js +457 -0
  40. package/src/rules/no-disabled-certificate-validation/index.d.ts +6 -0
  41. package/src/rules/no-disabled-certificate-validation/index.js +61 -0
  42. package/src/rules/no-dynamic-dependency-loading/index.d.ts +8 -0
  43. package/src/rules/no-dynamic-dependency-loading/index.js +51 -0
  44. package/src/rules/no-electron-security-issues/index.d.ts +10 -0
  45. package/src/rules/no-electron-security-issues/index.js +423 -0
  46. package/src/rules/no-exposed-debug-endpoints/index.d.ts +6 -0
  47. package/src/rules/no-exposed-debug-endpoints/index.js +62 -0
  48. package/src/rules/no-exposed-sensitive-data/index.d.ts +11 -0
  49. package/src/rules/no-exposed-sensitive-data/index.js +340 -0
  50. package/src/rules/no-format-string-injection/index.d.ts +17 -0
  51. package/src/rules/no-format-string-injection/index.js +660 -0
  52. package/src/rules/no-graphql-injection/index.d.ts +12 -0
  53. package/src/rules/no-graphql-injection/index.js +411 -0
  54. package/src/rules/no-hardcoded-credentials/index.d.ts +26 -0
  55. package/src/rules/no-hardcoded-credentials/index.js +376 -0
  56. package/src/rules/no-hardcoded-session-tokens/index.d.ts +6 -0
  57. package/src/rules/no-hardcoded-session-tokens/index.js +59 -0
  58. package/src/rules/no-http-urls/index.d.ts +12 -0
  59. package/src/rules/no-http-urls/index.js +114 -0
  60. package/src/rules/no-improper-sanitization/index.d.ts +12 -0
  61. package/src/rules/no-improper-sanitization/index.js +411 -0
  62. package/src/rules/no-improper-type-validation/index.d.ts +10 -0
  63. package/src/rules/no-improper-type-validation/index.js +475 -0
  64. package/src/rules/no-insecure-comparison/index.d.ts +7 -0
  65. package/src/rules/no-insecure-comparison/index.js +193 -0
  66. package/src/rules/no-insecure-redirects/index.d.ts +7 -0
  67. package/src/rules/no-insecure-redirects/index.js +216 -0
  68. package/src/rules/no-insecure-websocket/index.d.ts +6 -0
  69. package/src/rules/no-insecure-websocket/index.js +61 -0
  70. package/src/rules/no-ldap-injection/index.d.ts +10 -0
  71. package/src/rules/no-ldap-injection/index.js +455 -0
  72. package/src/rules/no-missing-authentication/index.d.ts +13 -0
  73. package/src/rules/no-missing-authentication/index.js +333 -0
  74. package/src/rules/no-missing-cors-check/index.d.ts +9 -0
  75. package/src/rules/no-missing-cors-check/index.js +399 -0
  76. package/src/rules/no-missing-csrf-protection/index.d.ts +11 -0
  77. package/src/rules/no-missing-csrf-protection/index.js +180 -0
  78. package/src/rules/no-missing-security-headers/index.d.ts +7 -0
  79. package/src/rules/no-missing-security-headers/index.js +218 -0
  80. package/src/rules/no-password-in-url/index.d.ts +8 -0
  81. package/src/rules/no-password-in-url/index.js +54 -0
  82. package/src/rules/no-permissive-cors/index.d.ts +8 -0
  83. package/src/rules/no-permissive-cors/index.js +65 -0
  84. package/src/rules/no-pii-in-logs/index.d.ts +8 -0
  85. package/src/rules/no-pii-in-logs/index.js +70 -0
  86. package/src/rules/no-privilege-escalation/index.d.ts +13 -0
  87. package/src/rules/no-privilege-escalation/index.js +321 -0
  88. package/src/rules/no-redos-vulnerable-regex/index.d.ts +7 -0
  89. package/src/rules/no-redos-vulnerable-regex/index.js +306 -0
  90. package/src/rules/no-sensitive-data-exposure/index.d.ts +11 -0
  91. package/src/rules/no-sensitive-data-exposure/index.js +250 -0
  92. package/src/rules/no-sensitive-data-in-analytics/index.d.ts +8 -0
  93. package/src/rules/no-sensitive-data-in-analytics/index.js +62 -0
  94. package/src/rules/no-sensitive-data-in-cache/index.d.ts +8 -0
  95. package/src/rules/no-sensitive-data-in-cache/index.js +52 -0
  96. package/src/rules/no-toctou-vulnerability/index.d.ts +7 -0
  97. package/src/rules/no-toctou-vulnerability/index.js +208 -0
  98. package/src/rules/no-tracking-without-consent/index.d.ts +6 -0
  99. package/src/rules/no-tracking-without-consent/index.js +67 -0
  100. package/src/rules/no-unchecked-loop-condition/index.d.ts +12 -0
  101. package/src/rules/no-unchecked-loop-condition/index.js +646 -0
  102. package/src/rules/no-unencrypted-transmission/index.d.ts +11 -0
  103. package/src/rules/no-unencrypted-transmission/index.js +236 -0
  104. package/src/rules/no-unescaped-url-parameter/index.d.ts +9 -0
  105. package/src/rules/no-unescaped-url-parameter/index.js +355 -0
  106. package/src/rules/no-unlimited-resource-allocation/index.d.ts +12 -0
  107. package/src/rules/no-unlimited-resource-allocation/index.js +643 -0
  108. package/src/rules/no-unsafe-deserialization/index.d.ts +10 -0
  109. package/src/rules/no-unsafe-deserialization/index.js +491 -0
  110. package/src/rules/no-unsafe-dynamic-require/index.d.ts +5 -0
  111. package/src/rules/no-unsafe-dynamic-require/index.js +106 -0
  112. package/src/rules/no-unsafe-regex-construction/index.d.ts +9 -0
  113. package/src/rules/no-unsafe-regex-construction/index.js +291 -0
  114. package/src/rules/no-unvalidated-deeplinks/index.d.ts +6 -0
  115. package/src/rules/no-unvalidated-deeplinks/index.js +62 -0
  116. package/src/rules/no-unvalidated-user-input/index.d.ts +9 -0
  117. package/src/rules/no-unvalidated-user-input/index.js +420 -0
  118. package/src/rules/no-verbose-error-messages/index.d.ts +8 -0
  119. package/src/rules/no-verbose-error-messages/index.js +68 -0
  120. package/src/rules/no-weak-password-recovery/index.d.ts +12 -0
  121. package/src/rules/no-weak-password-recovery/index.js +424 -0
  122. package/src/rules/no-xpath-injection/index.d.ts +10 -0
  123. package/src/rules/no-xpath-injection/index.js +487 -0
  124. package/src/rules/no-xxe-injection/index.d.ts +7 -0
  125. package/src/rules/no-xxe-injection/index.js +266 -0
  126. package/src/rules/no-zip-slip/index.d.ts +9 -0
  127. package/src/rules/no-zip-slip/index.js +445 -0
  128. package/src/rules/require-backend-authorization/index.d.ts +6 -0
  129. package/src/rules/require-backend-authorization/index.js +60 -0
  130. package/src/rules/require-code-minification/index.d.ts +8 -0
  131. package/src/rules/require-code-minification/index.js +47 -0
  132. package/src/rules/require-csp-headers/index.d.ts +6 -0
  133. package/src/rules/require-csp-headers/index.js +64 -0
  134. package/src/rules/require-data-minimization/index.d.ts +8 -0
  135. package/src/rules/require-data-minimization/index.js +53 -0
  136. package/src/rules/require-dependency-integrity/index.d.ts +6 -0
  137. package/src/rules/require-dependency-integrity/index.js +64 -0
  138. package/src/rules/require-https-only/index.d.ts +8 -0
  139. package/src/rules/require-https-only/index.js +62 -0
  140. package/src/rules/require-mime-type-validation/index.d.ts +6 -0
  141. package/src/rules/require-mime-type-validation/index.js +66 -0
  142. package/src/rules/require-network-timeout/index.d.ts +8 -0
  143. package/src/rules/require-network-timeout/index.js +50 -0
  144. package/src/rules/require-package-lock/index.d.ts +8 -0
  145. package/src/rules/require-package-lock/index.js +63 -0
  146. package/src/rules/require-secure-credential-storage/index.d.ts +8 -0
  147. package/src/rules/require-secure-credential-storage/index.js +50 -0
  148. package/src/rules/require-secure-defaults/index.d.ts +8 -0
  149. package/src/rules/require-secure-defaults/index.js +47 -0
  150. package/src/rules/require-secure-deletion/index.d.ts +8 -0
  151. package/src/rules/require-secure-deletion/index.js +44 -0
  152. package/src/rules/require-storage-encryption/index.d.ts +8 -0
  153. package/src/rules/require-storage-encryption/index.js +50 -0
  154. package/src/rules/require-url-validation/index.d.ts +6 -0
  155. package/src/rules/require-url-validation/index.js +72 -0
  156. package/src/types/index.d.ts +106 -0
  157. package/src/types/index.js +16 -0
  158. package/src/index.ts +0 -605
  159. package/src/rules/__tests__/integration-demo.test.ts +0 -290
  160. package/src/rules/__tests__/integration-llm.test.ts +0 -89
  161. package/src/rules/database-injection/database-injection.test.ts +0 -456
  162. package/src/rules/database-injection/index.ts +0 -488
  163. package/src/rules/detect-child-process/detect-child-process.test.ts +0 -207
  164. package/src/rules/detect-child-process/index.ts +0 -634
  165. package/src/rules/detect-eval-with-expression/detect-eval-with-expression.test.ts +0 -416
  166. package/src/rules/detect-eval-with-expression/index.ts +0 -463
  167. package/src/rules/detect-mixed-content/detect-mixed-content.test.ts +0 -28
  168. package/src/rules/detect-mixed-content/index.ts +0 -52
  169. package/src/rules/detect-non-literal-fs-filename/detect-non-literal-fs-filename.test.ts +0 -269
  170. package/src/rules/detect-non-literal-fs-filename/index.ts +0 -551
  171. package/src/rules/detect-non-literal-regexp/detect-non-literal-regexp.test.ts +0 -189
  172. package/src/rules/detect-non-literal-regexp/index.ts +0 -490
  173. package/src/rules/detect-object-injection/detect-object-injection.test.ts +0 -440
  174. package/src/rules/detect-object-injection/index.ts +0 -674
  175. package/src/rules/detect-suspicious-dependencies/detect-suspicious-dependencies.test.ts +0 -32
  176. package/src/rules/detect-suspicious-dependencies/index.ts +0 -84
  177. package/src/rules/detect-weak-password-validation/detect-weak-password-validation.test.ts +0 -31
  178. package/src/rules/detect-weak-password-validation/index.ts +0 -68
  179. package/src/rules/no-allow-arbitrary-loads/index.ts +0 -54
  180. package/src/rules/no-allow-arbitrary-loads/no-allow-arbitrary-loads.test.ts +0 -28
  181. package/src/rules/no-arbitrary-file-access/index.ts +0 -238
  182. package/src/rules/no-arbitrary-file-access/no-arbitrary-file-access.test.ts +0 -119
  183. package/src/rules/no-buffer-overread/index.ts +0 -724
  184. package/src/rules/no-buffer-overread/no-buffer-overread.test.ts +0 -313
  185. package/src/rules/no-clickjacking/index.ts +0 -481
  186. package/src/rules/no-clickjacking/no-clickjacking.test.ts +0 -253
  187. package/src/rules/no-client-side-auth-logic/index.ts +0 -81
  188. package/src/rules/no-client-side-auth-logic/no-client-side-auth-logic.test.ts +0 -33
  189. package/src/rules/no-credentials-in-query-params/index.ts +0 -69
  190. package/src/rules/no-credentials-in-query-params/no-credentials-in-query-params.test.ts +0 -33
  191. package/src/rules/no-credentials-in-storage-api/index.ts +0 -64
  192. package/src/rules/no-credentials-in-storage-api/no-credentials-in-storage-api.test.ts +0 -31
  193. package/src/rules/no-data-in-temp-storage/index.ts +0 -75
  194. package/src/rules/no-data-in-temp-storage/no-data-in-temp-storage.test.ts +0 -33
  195. package/src/rules/no-debug-code-in-production/index.ts +0 -59
  196. package/src/rules/no-debug-code-in-production/no-debug-code-in-production.test.ts +0 -26
  197. package/src/rules/no-directive-injection/index.ts +0 -551
  198. package/src/rules/no-directive-injection/no-directive-injection.test.ts +0 -305
  199. package/src/rules/no-disabled-certificate-validation/index.ts +0 -72
  200. package/src/rules/no-disabled-certificate-validation/no-disabled-certificate-validation.test.ts +0 -33
  201. package/src/rules/no-document-cookie/index.ts +0 -113
  202. package/src/rules/no-document-cookie/no-document-cookie.test.ts +0 -382
  203. package/src/rules/no-dynamic-dependency-loading/index.ts +0 -60
  204. package/src/rules/no-dynamic-dependency-loading/no-dynamic-dependency-loading.test.ts +0 -27
  205. package/src/rules/no-electron-security-issues/index.ts +0 -504
  206. package/src/rules/no-electron-security-issues/no-electron-security-issues.test.ts +0 -324
  207. package/src/rules/no-exposed-debug-endpoints/index.ts +0 -73
  208. package/src/rules/no-exposed-debug-endpoints/no-exposed-debug-endpoints.test.ts +0 -40
  209. package/src/rules/no-exposed-sensitive-data/index.ts +0 -428
  210. package/src/rules/no-exposed-sensitive-data/no-exposed-sensitive-data.test.ts +0 -75
  211. package/src/rules/no-format-string-injection/index.ts +0 -801
  212. package/src/rules/no-format-string-injection/no-format-string-injection.test.ts +0 -437
  213. package/src/rules/no-graphql-injection/index.ts +0 -508
  214. package/src/rules/no-graphql-injection/no-graphql-injection.test.ts +0 -371
  215. package/src/rules/no-hardcoded-credentials/index.ts +0 -478
  216. package/src/rules/no-hardcoded-credentials/no-hardcoded-credentials.test.ts +0 -639
  217. package/src/rules/no-hardcoded-session-tokens/index.ts +0 -69
  218. package/src/rules/no-hardcoded-session-tokens/no-hardcoded-session-tokens.test.ts +0 -42
  219. package/src/rules/no-http-urls/index.ts +0 -131
  220. package/src/rules/no-http-urls/no-http-urls.test.ts +0 -60
  221. package/src/rules/no-improper-sanitization/index.ts +0 -502
  222. package/src/rules/no-improper-sanitization/no-improper-sanitization.test.ts +0 -156
  223. package/src/rules/no-improper-type-validation/index.ts +0 -572
  224. package/src/rules/no-improper-type-validation/no-improper-type-validation.test.ts +0 -372
  225. package/src/rules/no-insecure-comparison/index.ts +0 -232
  226. package/src/rules/no-insecure-comparison/no-insecure-comparison.test.ts +0 -218
  227. package/src/rules/no-insecure-cookie-settings/index.ts +0 -391
  228. package/src/rules/no-insecure-cookie-settings/no-insecure-cookie-settings.test.ts +0 -409
  229. package/src/rules/no-insecure-jwt/index.ts +0 -467
  230. package/src/rules/no-insecure-jwt/no-insecure-jwt.test.ts +0 -259
  231. package/src/rules/no-insecure-redirects/index.ts +0 -267
  232. package/src/rules/no-insecure-redirects/no-insecure-redirects.test.ts +0 -108
  233. package/src/rules/no-insecure-websocket/index.ts +0 -72
  234. package/src/rules/no-insecure-websocket/no-insecure-websocket.test.ts +0 -42
  235. package/src/rules/no-insufficient-postmessage-validation/index.ts +0 -497
  236. package/src/rules/no-insufficient-postmessage-validation/no-insufficient-postmessage-validation.test.ts +0 -360
  237. package/src/rules/no-insufficient-random/index.ts +0 -288
  238. package/src/rules/no-insufficient-random/no-insufficient-random.test.ts +0 -246
  239. package/src/rules/no-ldap-injection/index.ts +0 -547
  240. package/src/rules/no-ldap-injection/no-ldap-injection.test.ts +0 -317
  241. package/src/rules/no-missing-authentication/index.ts +0 -408
  242. package/src/rules/no-missing-authentication/no-missing-authentication.test.ts +0 -350
  243. package/src/rules/no-missing-cors-check/index.ts +0 -453
  244. package/src/rules/no-missing-cors-check/no-missing-cors-check.test.ts +0 -392
  245. package/src/rules/no-missing-csrf-protection/index.ts +0 -229
  246. package/src/rules/no-missing-csrf-protection/no-missing-csrf-protection.test.ts +0 -222
  247. package/src/rules/no-missing-security-headers/index.ts +0 -266
  248. package/src/rules/no-missing-security-headers/no-missing-security-headers.test.ts +0 -98
  249. package/src/rules/no-password-in-url/index.ts +0 -64
  250. package/src/rules/no-password-in-url/no-password-in-url.test.ts +0 -27
  251. package/src/rules/no-permissive-cors/index.ts +0 -78
  252. package/src/rules/no-permissive-cors/no-permissive-cors.test.ts +0 -28
  253. package/src/rules/no-pii-in-logs/index.ts +0 -83
  254. package/src/rules/no-pii-in-logs/no-pii-in-logs.test.ts +0 -26
  255. package/src/rules/no-postmessage-origin-wildcard/index.ts +0 -67
  256. package/src/rules/no-postmessage-origin-wildcard/no-postmessage-origin-wildcard.test.ts +0 -27
  257. package/src/rules/no-privilege-escalation/index.ts +0 -403
  258. package/src/rules/no-privilege-escalation/no-privilege-escalation.test.ts +0 -306
  259. package/src/rules/no-redos-vulnerable-regex/index.ts +0 -379
  260. package/src/rules/no-redos-vulnerable-regex/no-redos-vulnerable-regex.test.ts +0 -83
  261. package/src/rules/no-sensitive-data-exposure/index.ts +0 -294
  262. package/src/rules/no-sensitive-data-exposure/no-sensitive-data-exposure.test.ts +0 -262
  263. package/src/rules/no-sensitive-data-in-analytics/index.ts +0 -73
  264. package/src/rules/no-sensitive-data-in-analytics/no-sensitive-data-in-analytics.test.ts +0 -42
  265. package/src/rules/no-sensitive-data-in-cache/index.ts +0 -59
  266. package/src/rules/no-sensitive-data-in-cache/no-sensitive-data-in-cache.test.ts +0 -32
  267. package/src/rules/no-sql-injection/index.ts +0 -424
  268. package/src/rules/no-sql-injection/no-sql-injection.test.ts +0 -303
  269. package/src/rules/no-timing-attack/index.ts +0 -552
  270. package/src/rules/no-timing-attack/no-timing-attack.test.ts +0 -348
  271. package/src/rules/no-toctou-vulnerability/index.ts +0 -250
  272. package/src/rules/no-toctou-vulnerability/no-toctou-vulnerability.test.ts +0 -60
  273. package/src/rules/no-tracking-without-consent/index.ts +0 -78
  274. package/src/rules/no-tracking-without-consent/no-tracking-without-consent.test.ts +0 -34
  275. package/src/rules/no-unchecked-loop-condition/index.ts +0 -781
  276. package/src/rules/no-unchecked-loop-condition/no-unchecked-loop-condition.test.ts +0 -459
  277. package/src/rules/no-unencrypted-local-storage/index.ts +0 -73
  278. package/src/rules/no-unencrypted-local-storage/no-unencrypted-local-storage.test.ts +0 -41
  279. package/src/rules/no-unencrypted-transmission/index.ts +0 -296
  280. package/src/rules/no-unencrypted-transmission/no-unencrypted-transmission.test.ts +0 -287
  281. package/src/rules/no-unescaped-url-parameter/index.ts +0 -424
  282. package/src/rules/no-unescaped-url-parameter/no-unescaped-url-parameter.test.ts +0 -263
  283. package/src/rules/no-unlimited-resource-allocation/index.ts +0 -767
  284. package/src/rules/no-unlimited-resource-allocation/no-unlimited-resource-allocation.test.ts +0 -544
  285. package/src/rules/no-unsafe-deserialization/index.ts +0 -593
  286. package/src/rules/no-unsafe-deserialization/no-unsafe-deserialization.test.ts +0 -310
  287. package/src/rules/no-unsafe-dynamic-require/index.ts +0 -125
  288. package/src/rules/no-unsafe-dynamic-require/no-unsafe-dynamic-require.test.ts +0 -151
  289. package/src/rules/no-unsafe-regex-construction/index.ts +0 -370
  290. package/src/rules/no-unsafe-regex-construction/no-unsafe-regex-construction.test.ts +0 -181
  291. package/src/rules/no-unsanitized-html/index.ts +0 -400
  292. package/src/rules/no-unsanitized-html/no-unsanitized-html.test.ts +0 -488
  293. package/src/rules/no-unvalidated-deeplinks/index.ts +0 -73
  294. package/src/rules/no-unvalidated-deeplinks/no-unvalidated-deeplinks.test.ts +0 -29
  295. package/src/rules/no-unvalidated-user-input/index.ts +0 -498
  296. package/src/rules/no-unvalidated-user-input/no-unvalidated-user-input.test.ts +0 -463
  297. package/src/rules/no-verbose-error-messages/index.ts +0 -83
  298. package/src/rules/no-verbose-error-messages/no-verbose-error-messages.test.ts +0 -34
  299. package/src/rules/no-weak-crypto/index.ts +0 -447
  300. package/src/rules/no-weak-crypto/no-weak-crypto.test.ts +0 -297
  301. package/src/rules/no-weak-password-recovery/index.ts +0 -509
  302. package/src/rules/no-weak-password-recovery/no-weak-password-recovery.test.ts +0 -184
  303. package/src/rules/no-xpath-injection/index.ts +0 -596
  304. package/src/rules/no-xpath-injection/no-xpath-injection.test.ts +0 -405
  305. package/src/rules/no-xxe-injection/index.ts +0 -342
  306. package/src/rules/no-xxe-injection/no-xxe-injection.test.ts +0 -122
  307. package/src/rules/no-zip-slip/index.ts +0 -526
  308. package/src/rules/no-zip-slip/no-zip-slip.test.ts +0 -305
  309. package/src/rules/require-backend-authorization/index.ts +0 -71
  310. package/src/rules/require-backend-authorization/require-backend-authorization.test.ts +0 -31
  311. package/src/rules/require-code-minification/index.ts +0 -54
  312. package/src/rules/require-code-minification/require-code-minification.test.ts +0 -30
  313. package/src/rules/require-csp-headers/index.ts +0 -74
  314. package/src/rules/require-csp-headers/require-csp-headers.test.ts +0 -34
  315. package/src/rules/require-data-minimization/index.ts +0 -65
  316. package/src/rules/require-data-minimization/require-data-minimization.test.ts +0 -31
  317. package/src/rules/require-dependency-integrity/index.ts +0 -78
  318. package/src/rules/require-dependency-integrity/require-dependency-integrity.test.ts +0 -44
  319. package/src/rules/require-https-only/index.ts +0 -75
  320. package/src/rules/require-https-only/require-https-only.test.ts +0 -26
  321. package/src/rules/require-mime-type-validation/index.ts +0 -77
  322. package/src/rules/require-mime-type-validation/require-mime-type-validation.test.ts +0 -32
  323. package/src/rules/require-network-timeout/index.ts +0 -58
  324. package/src/rules/require-network-timeout/require-network-timeout.test.ts +0 -26
  325. package/src/rules/require-package-lock/index.ts +0 -75
  326. package/src/rules/require-package-lock/require-package-lock.test.ts +0 -27
  327. package/src/rules/require-secure-credential-storage/index.ts +0 -60
  328. package/src/rules/require-secure-credential-storage/require-secure-credential-storage.test.ts +0 -26
  329. package/src/rules/require-secure-defaults/index.ts +0 -54
  330. package/src/rules/require-secure-defaults/require-secure-defaults.test.ts +0 -26
  331. package/src/rules/require-secure-deletion/index.ts +0 -52
  332. package/src/rules/require-secure-deletion/require-secure-deletion.test.ts +0 -29
  333. package/src/rules/require-storage-encryption/index.ts +0 -60
  334. package/src/rules/require-storage-encryption/require-storage-encryption.test.ts +0 -26
  335. package/src/rules/require-url-validation/index.ts +0 -85
  336. package/src/rules/require-url-validation/require-url-validation.test.ts +0 -32
  337. package/src/types/index.ts +0 -235
@@ -1,724 +0,0 @@
1
- /**
2
- * ESLint Rule: no-buffer-overread
3
- * Detects buffer access beyond bounds (CWE-126)
4
- *
5
- * Buffer overread occurs when reading from buffers beyond their allocated
6
- * length, potentially leading to information disclosure, crashes, or
7
- * other security issues.
8
- *
9
- * False Positive Reduction:
10
- * This rule uses security utilities to reduce false positives by detecting:
11
- * - Safe buffer access patterns
12
- * - Bounds checking operations
13
- * - JSDoc annotations (@safe, @validated)
14
- * - Input validation functions
15
- */
16
- import type { TSESLint, TSESTree, SecurityRuleOptions } from '@interlace/eslint-devkit';
17
- import { AST_NODE_TYPES, createRule, formatLLMMessage, MessageIcons, createSafetyChecker } from '@interlace/eslint-devkit';
18
-
19
- type MessageIds =
20
- | 'bufferOverread'
21
- | 'unsafeBufferAccess'
22
- | 'missingBoundsCheck'
23
- | 'negativeBufferIndex'
24
- | 'userControlledBufferIndex'
25
- | 'unsafeBufferSlice'
26
- | 'bufferLengthNotChecked'
27
- | 'useSafeBufferAccess'
28
- | 'validateBufferIndices'
29
- | 'checkBufferBounds'
30
- | 'strategyBoundsChecking'
31
- | 'strategyInputValidation'
32
- | 'strategySafeBuffers';
33
-
34
- export interface Options extends SecurityRuleOptions {
35
- /** Buffer methods to check for bounds safety */
36
- bufferMethods?: string[];
37
-
38
- /** Functions that validate buffer indices */
39
- boundsCheckFunctions?: string[];
40
-
41
- /** Buffer types to monitor */
42
- bufferTypes?: string[];
43
-
44
- /** Additional function names to consider as buffer index validators */
45
- trustedSanitizers?: string[];
46
-
47
- /** Additional JSDoc annotations to consider as safe markers */
48
- strictMode?: boolean;
49
- }
50
-
51
- type RuleOptions = [Options?];
52
-
53
-
54
- export const noBufferOverread = createRule<RuleOptions, MessageIds>({
55
- name: 'no-buffer-overread',
56
- meta: {
57
- type: 'problem',
58
- docs: {
59
- description: 'Detects buffer access beyond bounds',
60
- },
61
- fixable: 'code',
62
- hasSuggestions: true,
63
- messages: {
64
- bufferOverread: formatLLMMessage({
65
- icon: MessageIcons.SECURITY,
66
- issueName: 'Buffer Overread',
67
- cwe: 'CWE-126',
68
- description: 'Buffer access beyond allocated bounds',
69
- severity: '{{severity}}',
70
- fix: '{{safeAlternative}}',
71
- documentationLink: 'https://cwe.mitre.org/data/definitions/126.html',
72
- }),
73
- unsafeBufferAccess: formatLLMMessage({
74
- icon: MessageIcons.SECURITY,
75
- issueName: 'Unsafe Buffer Access',
76
- cwe: 'CWE-126',
77
- description: 'Buffer accessed without bounds validation',
78
- severity: 'HIGH',
79
- fix: 'Add bounds check before buffer access',
80
- documentationLink: 'https://nodejs.org/api/buffer.html',
81
- }),
82
- missingBoundsCheck: formatLLMMessage({
83
- icon: MessageIcons.SECURITY,
84
- issueName: 'Missing Bounds Check',
85
- cwe: 'CWE-126',
86
- description: 'Buffer operation missing bounds validation',
87
- severity: 'MEDIUM',
88
- fix: 'Validate indices before buffer operations',
89
- documentationLink: 'https://cwe.mitre.org/data/definitions/126.html',
90
- }),
91
- negativeBufferIndex: formatLLMMessage({
92
- icon: MessageIcons.SECURITY,
93
- issueName: 'Negative Buffer Index',
94
- cwe: 'CWE-126',
95
- description: 'Negative index used for buffer access',
96
- severity: 'MEDIUM',
97
- fix: 'Ensure buffer indices are non-negative',
98
- documentationLink: 'https://nodejs.org/api/buffer.html',
99
- }),
100
- userControlledBufferIndex: formatLLMMessage({
101
- icon: MessageIcons.SECURITY,
102
- issueName: 'User Controlled Buffer Index',
103
- cwe: 'CWE-126',
104
- description: 'Buffer accessed with user-controlled index',
105
- severity: 'HIGH',
106
- fix: 'Validate user input before using as buffer index',
107
- documentationLink: 'https://cwe.mitre.org/data/definitions/126.html',
108
- }),
109
- unsafeBufferSlice: formatLLMMessage({
110
- icon: MessageIcons.SECURITY,
111
- issueName: 'Unsafe Buffer Slice',
112
- cwe: 'CWE-126',
113
- description: 'Buffer slice with unvalidated indices',
114
- severity: 'MEDIUM',
115
- fix: 'Validate slice start/end indices',
116
- documentationLink: 'https://nodejs.org/api/buffer.html#bufslicestart-end',
117
- }),
118
- bufferLengthNotChecked: formatLLMMessage({
119
- icon: MessageIcons.SECURITY,
120
- issueName: 'Buffer Length Not Checked',
121
- cwe: 'CWE-126',
122
- description: 'Buffer length not validated before access',
123
- severity: 'MEDIUM',
124
- fix: 'Check buffer.length before operations',
125
- documentationLink: 'https://nodejs.org/api/buffer.html#buflength',
126
- }),
127
- useSafeBufferAccess: formatLLMMessage({
128
- icon: MessageIcons.INFO,
129
- issueName: 'Use Safe Buffer Access',
130
- description: 'Use bounds-checked buffer access methods',
131
- severity: 'LOW',
132
- fix: 'Use buffer.read*() with offset validation or safe wrapper functions',
133
- documentationLink: 'https://nodejs.org/api/buffer.html',
134
- }),
135
- validateBufferIndices: formatLLMMessage({
136
- icon: MessageIcons.INFO,
137
- issueName: 'Validate Buffer Indices',
138
- description: 'Validate buffer indices before use',
139
- severity: 'LOW',
140
- fix: 'Check 0 <= index < buffer.length',
141
- documentationLink: 'https://cwe.mitre.org/data/definitions/126.html',
142
- }),
143
- checkBufferBounds: formatLLMMessage({
144
- icon: MessageIcons.INFO,
145
- issueName: 'Check Buffer Bounds',
146
- description: 'Always check buffer bounds',
147
- severity: 'LOW',
148
- fix: 'Validate buffer operations against buffer.length',
149
- documentationLink: 'https://nodejs.org/api/buffer.html#buflength',
150
- }),
151
- strategyBoundsChecking: formatLLMMessage({
152
- icon: MessageIcons.STRATEGY,
153
- issueName: 'Bounds Checking Strategy',
154
- description: 'Implement comprehensive bounds checking',
155
- severity: 'LOW',
156
- fix: 'Validate all buffer indices and lengths before operations',
157
- documentationLink: 'https://cwe.mitre.org/data/definitions/126.html',
158
- }),
159
- strategyInputValidation: formatLLMMessage({
160
- icon: MessageIcons.STRATEGY,
161
- issueName: 'Input Validation Strategy',
162
- description: 'Validate user input used as buffer indices',
163
- severity: 'LOW',
164
- fix: 'Sanitize and validate all user input before buffer operations',
165
- documentationLink: 'https://nodejs.org/api/buffer.html',
166
- }),
167
- strategySafeBuffers: formatLLMMessage({
168
- icon: MessageIcons.STRATEGY,
169
- issueName: 'Safe Buffer Strategy',
170
- description: 'Use safe buffer wrapper libraries',
171
- severity: 'LOW',
172
- fix: 'Use libraries that provide bounds-checked buffer operations',
173
- documentationLink: 'https://www.npmjs.com/package/safe-buffer',
174
- })
175
- },
176
- schema: [
177
- {
178
- type: 'object',
179
- properties: {
180
- bufferMethods: {
181
- type: 'array',
182
- items: { type: 'string' },
183
- default: ['readUInt8', 'readUInt16LE', 'readUInt32LE', 'readInt8', 'readInt16LE', 'readInt32LE', 'writeUInt8', 'writeUInt16LE', 'writeUInt32LE', 'slice', 'copy'],
184
- },
185
- boundsCheckFunctions: {
186
- type: 'array',
187
- items: { type: 'string' },
188
- default: ['validateIndex', 'checkBounds', 'safeIndex', 'validateBufferIndex'],
189
- },
190
- bufferTypes: {
191
- type: 'array',
192
- items: { type: 'string' },
193
- default: ['Buffer', 'Uint8Array', 'ArrayBuffer', 'DataView'],
194
- },
195
- trustedSanitizers: {
196
- type: 'array',
197
- items: { type: 'string' },
198
- default: [],
199
- description: 'Additional function names to consider as buffer index validators',
200
- },
201
- trustedAnnotations: {
202
- type: 'array',
203
- items: { type: 'string' },
204
- default: [],
205
- description: 'Additional JSDoc annotations to consider as safe markers',
206
- },
207
- strictMode: {
208
- type: 'boolean',
209
- default: false,
210
- description: 'Disable all false positive detection (strict mode)',
211
- },
212
- },
213
- additionalProperties: false,
214
- },
215
- ],
216
- },
217
- defaultOptions: [
218
- {
219
- bufferMethods: ['readUInt8', 'readUInt16LE', 'readUInt32LE', 'readInt8', 'readInt16LE', 'readInt32LE', 'writeUInt8', 'writeUInt16LE', 'writeUInt32LE', 'slice', 'copy'],
220
- boundsCheckFunctions: ['validateIndex', 'checkBounds', 'safeIndex', 'validateBufferIndex'],
221
- bufferTypes: ['Buffer', 'Uint8Array', 'ArrayBuffer', 'DataView'],
222
- trustedSanitizers: [],
223
- trustedAnnotations: [],
224
- strictMode: false,
225
- },
226
- ],
227
- create(context: TSESLint.RuleContext<MessageIds, RuleOptions>) {
228
- const options = context.options[0] || {};
229
- const {
230
- bufferMethods = ['readUInt8', 'readUInt16LE', 'readUInt32LE', 'readInt8', 'readInt16LE', 'readInt32LE', 'writeUInt8', 'writeUInt16LE', 'writeUInt32LE', 'slice', 'copy'],
231
- boundsCheckFunctions = ['validateIndex', 'checkBounds', 'safeIndex', 'validateBufferIndex'],
232
- bufferTypes = ['Buffer', 'Uint8Array', 'ArrayBuffer', 'DataView'],
233
- trustedSanitizers = [],
234
- trustedAnnotations = [],
235
- strictMode = false,
236
- }: Options = options;
237
-
238
- const sourceCode = context.sourceCode || context.sourceCode;
239
- const filename = context.filename || context.getFilename();
240
-
241
- // Create safety checker for false positive detection
242
- const safetyChecker = createSafetyChecker({
243
- trustedSanitizers,
244
- trustedAnnotations,
245
- trustedOrmPatterns: [],
246
- strictMode,
247
- });
248
-
249
- // Pre-compute Sets for O(1) lookups (performance optimization)
250
- const bufferTypesSet = new Set(bufferTypes.map(t => t.toLowerCase()));
251
- const userControlledKeywords = new Set(['req', 'request', 'query', 'params', 'input', 'user', 'offset', 'index', 'body']);
252
-
253
- // Track buffer variables
254
- const bufferVars = new Set<string>();
255
-
256
- /**
257
- * Check if variable is a buffer type
258
- * Uses Set-based lookup for O(1) performance
259
- */
260
- const isBufferType = (varName: string): boolean => {
261
- if (bufferVars.has(varName)) return true;
262
- const lowerName = varName.toLowerCase();
263
- for (const type of bufferTypesSet) {
264
- if (lowerName.includes(type)) return true;
265
- }
266
- return false;
267
- };
268
-
269
- /**
270
- * Check if index is user-controlled
271
- * Uses Set-based keyword matching for O(1) lookups
272
- */
273
- const isUserControlledIndex = (indexNode: TSESTree.Node): boolean => {
274
- if (indexNode.type === 'Identifier') {
275
- const varName = indexNode.name.toLowerCase();
276
- // Check each part of the variable name against keywords Set
277
- for (const keyword of userControlledKeywords) {
278
- if (varName.includes(keyword)) return true;
279
- }
280
-
281
- // Trace variable definition
282
- let currentScope = sourceCode.getScope(indexNode);
283
- let variable = null;
284
- while(currentScope) {
285
- variable = currentScope.variables.find(v => v.name === indexNode.name);
286
- if (variable) break;
287
- currentScope = currentScope.upper;
288
- }
289
-
290
- if (variable && variable.defs.length > 0) {
291
- const def = variable.defs[0];
292
- if (def.type === 'Variable' && def.node.init) {
293
- const init = def.node.init;
294
-
295
- // Check MemberExpression involving user keywords (e.g. req.body.index)
296
- if (init.type === 'MemberExpression') {
297
- const objectText = sourceCode.getText(init.object).toLowerCase();
298
- const propertyText = sourceCode.getText(init.property).toLowerCase();
299
-
300
- const keywords = ['req', 'request', 'query', 'params', 'input', 'user', 'body'];
301
- if (keywords.some(k => objectText.includes(k) || propertyText.includes(k))) {
302
- return true;
303
- }
304
- }
305
-
306
- // Check CallExpression with user-controlled arguments (Number(req.query.index), parseInt(), etc.)
307
- if (init.type === AST_NODE_TYPES.CallExpression) {
308
- // Check if callee is a type conversion function
309
- const typeConversionFunctions = ['number', 'parseint', 'parsefloat', 'string', 'boolean'];
310
- let isTypeConversion = false;
311
-
312
- if (init.callee.type === AST_NODE_TYPES.Identifier) {
313
- isTypeConversion = typeConversionFunctions.includes(init.callee.name.toLowerCase());
314
- }
315
-
316
- // If it's a type conversion, check if the argument is user-controlled
317
- if (isTypeConversion && init.arguments.length > 0) {
318
- return isUserControlledIndex(init.arguments[0]);
319
- }
320
- }
321
-
322
- // Recursive check for Identifier assignment
323
- if (init.type === 'Identifier' && init.name !== indexNode.name) {
324
- return isUserControlledIndex(init);
325
- }
326
- }
327
- }
328
- }
329
-
330
- // Check CallExpression arguments (Number(req.query.index))
331
- if (indexNode.type === AST_NODE_TYPES.CallExpression) {
332
- const typeConversionFunctions = ['Number', 'parseInt', 'parseFloat', 'String', 'Boolean'];
333
- if (indexNode.callee.type === AST_NODE_TYPES.Identifier &&
334
- typeConversionFunctions.includes(indexNode.callee.name)) {
335
- // Check if arguments are user-controlled
336
- for (const arg of indexNode.arguments) {
337
- if (isUserControlledIndex(arg)) {
338
- return true;
339
- }
340
- }
341
- }
342
- }
343
-
344
- // Check MemberExpression (req.query.index)
345
- if (indexNode.type === AST_NODE_TYPES.MemberExpression) {
346
- const text = sourceCode.getText(indexNode).toLowerCase();
347
- const keywords = ['req.', 'request.', 'query.', 'params.', 'body.', 'input.', 'user.'];
348
- if (keywords.some(k => text.includes(k))) {
349
- return true;
350
- }
351
- }
352
-
353
- return false;
354
- };
355
-
356
- /**
357
- * Check if index has been validated
358
- */
359
- const isIndexValidated = (indexNode: TSESTree.Node): boolean => {
360
- // If it's a literal number, check if it's non-negative
361
- if (indexNode.type === AST_NODE_TYPES.Literal && typeof indexNode.value === 'number') {
362
- return indexNode.value >= 0;
363
- }
364
-
365
- // If it's an identifier, check if it comes from a bounds check function
366
- if (indexNode.type === AST_NODE_TYPES.Identifier) {
367
- let current: TSESTree.Node | undefined = indexNode;
368
-
369
- // Walk up the AST to find where this variable was assigned
370
- while (current) {
371
- // Check if we're in a variable declaration
372
- if (current.type === AST_NODE_TYPES.VariableDeclarator &&
373
- current.id.type === AST_NODE_TYPES.Identifier &&
374
- current.id.name === indexNode.name &&
375
- current.init) {
376
-
377
- const init = current.init;
378
-
379
- // Check if assigned from a bounds check function
380
- if (init.type === AST_NODE_TYPES.CallExpression &&
381
- init.callee.type === AST_NODE_TYPES.Identifier &&
382
- boundsCheckFunctions.includes(init.callee.name)) {
383
- return true;
384
- }
385
-
386
- // Check if assigned from Math.min/max with buffer.length
387
- if (init.type === AST_NODE_TYPES.CallExpression &&
388
- init.callee.type === AST_NODE_TYPES.MemberExpression &&
389
- init.callee.object.type === AST_NODE_TYPES.Identifier &&
390
- init.callee.object.name === 'Math' &&
391
- init.callee.property.type === AST_NODE_TYPES.Identifier &&
392
- (init.callee.property.name === 'min' || init.callee.property.name === 'max')) {
393
- return true;
394
- }
395
-
396
- break;
397
- }
398
-
399
- // Check if it's a parameter in a function - assume validated if it's a function param
400
- if (current.type === AST_NODE_TYPES.FunctionDeclaration ||
401
- current.type === AST_NODE_TYPES.FunctionExpression ||
402
- current.type === AST_NODE_TYPES.ArrowFunctionExpression) {
403
- const params = current.params;
404
- for (const param of params) {
405
- if (param.type === AST_NODE_TYPES.Identifier && param.name === indexNode.name) {
406
- return true; // Function parameters are assumed validated
407
- }
408
- }
409
- }
410
-
411
- current = current.parent as TSESTree.Node;
412
- }
413
- }
414
-
415
- // Check if it's a call to a bounds check function directly
416
- if (indexNode.type === AST_NODE_TYPES.CallExpression &&
417
- indexNode.callee.type === AST_NODE_TYPES.Identifier &&
418
- boundsCheckFunctions.includes(indexNode.callee.name)) {
419
- return true;
420
- }
421
-
422
- return false;
423
- };
424
-
425
- /**
426
- * Check if there's a bounds check in the current scope
427
- */
428
- const hasBoundsCheck = (bufferName: string, indexNode: TSESTree.Node): boolean => {
429
- // Look for bounds checks in the current function scope
430
- let current: TSESTree.Node | undefined = indexNode;
431
-
432
- while (current) {
433
- // Check if we're in a function
434
- if (current.type === AST_NODE_TYPES.FunctionDeclaration ||
435
- current.type === AST_NODE_TYPES.FunctionExpression ||
436
- current.type === AST_NODE_TYPES.ArrowFunctionExpression) {
437
- break;
438
- }
439
-
440
- // Look for if statements that check bounds
441
- if (current.type === AST_NODE_TYPES.IfStatement) {
442
- const condition = current.test;
443
- const conditionText = sourceCode.getText(condition).toLowerCase();
444
-
445
- // Check for bounds checking patterns
446
- if (conditionText.includes(`${bufferName}.length`) &&
447
- (conditionText.includes('<') || conditionText.includes('<=') ||
448
- conditionText.includes('>') || conditionText.includes('>=') ||
449
- conditionText.includes('&&') || conditionText.includes('||'))) {
450
- return true;
451
- }
452
- }
453
-
454
- // Look for variable declarations that might be bounds checks
455
- if (current.type === AST_NODE_TYPES.VariableDeclaration) {
456
- for (const declarator of current.declarations) {
457
- if (declarator.init) {
458
- const initText = sourceCode.getText(declarator.init).toLowerCase();
459
- if (initText.includes(`${bufferName}.length`) &&
460
- (initText.includes('math.min') || initText.includes('math.max') ||
461
- initText.includes('mathmin') || initText.includes('mathmax'))) {
462
- return true;
463
- }
464
- }
465
- }
466
- }
467
-
468
- // Look for return statements or early returns that might indicate bounds checking
469
- if (current.type === AST_NODE_TYPES.ReturnStatement && current.argument) {
470
- const returnText = sourceCode.getText(current.argument).toLowerCase();
471
- if (returnText.includes(`${bufferName}.length`)) {
472
- return true;
473
- }
474
- }
475
-
476
- current = current.parent as TSESTree.Node;
477
- }
478
-
479
- return false;
480
- };
481
-
482
- /**
483
- * Check if index could be negative
484
- */
485
- const couldBeNegative = (indexNode: TSESTree.Node): boolean => {
486
- // Check for literal negative numbers
487
- // Check for literal negative numbers
488
- if (indexNode.type === AST_NODE_TYPES.Literal && typeof indexNode.value === 'number') {
489
- return indexNode.value < 0;
490
- }
491
-
492
- // Check for unary minus expressions like -1, -10, etc.
493
- if (indexNode.type === AST_NODE_TYPES.UnaryExpression &&
494
- indexNode.operator === '-' &&
495
- indexNode.argument.type === AST_NODE_TYPES.Literal &&
496
- typeof indexNode.argument.value === 'number') {
497
- return true; // -N is always negative for positive N
498
- }
499
-
500
- // Check for binary expressions that could be negative like userInput - 10
501
- if (indexNode.type === AST_NODE_TYPES.BinaryExpression && indexNode.operator === '-') {
502
- // userInput - 10 could be negative, we can't be sure statically
503
- return true; // Conservative: assume it could be negative
504
- }
505
-
506
- // For variables, we can't be sure, but we can check for obvious patterns
507
- if (indexNode.type === AST_NODE_TYPES.Identifier) {
508
- // Check if this variable is assigned a negative value somewhere
509
- // This is a simplified check - in practice we'd need more sophisticated analysis
510
- let current: TSESTree.Node | undefined = indexNode;
511
-
512
- while (current) {
513
- if (current.type === AST_NODE_TYPES.VariableDeclarator && current.init) {
514
- if (current.init.type === AST_NODE_TYPES.Literal &&
515
- typeof current.init.value === 'number' &&
516
- current.init.value < 0) {
517
- return true;
518
- }
519
- // Check for unary minus assignments
520
- if (current.init.type === AST_NODE_TYPES.UnaryExpression &&
521
- current.init.operator === '-' &&
522
- current.init.argument.type === AST_NODE_TYPES.Literal &&
523
- typeof current.init.argument.value === 'number') {
524
- return true;
525
- }
526
- }
527
- current = current.parent as TSESTree.Node;
528
- }
529
- }
530
-
531
- return false;
532
- };
533
-
534
- return {
535
- // Track buffer variable declarations
536
- VariableDeclarator(node: TSESTree.VariableDeclarator) {
537
- if (node.id.type === AST_NODE_TYPES.Identifier && node.init) {
538
- const varName = node.id.name;
539
-
540
- // Check if assigned a buffer type
541
- if (node.init.type === AST_NODE_TYPES.NewExpression &&
542
- node.init.callee.type === AST_NODE_TYPES.Identifier &&
543
- bufferTypes.includes(node.init.callee.name)) {
544
- bufferVars.add(varName);
545
- }
546
-
547
- // Check if assigned from Buffer.from() or Buffer.alloc()
548
- if (node.init.type === AST_NODE_TYPES.CallExpression &&
549
- node.init.callee.type === AST_NODE_TYPES.MemberExpression &&
550
- node.init.callee.object.type === AST_NODE_TYPES.Identifier &&
551
- node.init.callee.object.name === 'Buffer' &&
552
- node.init.callee.property.type === AST_NODE_TYPES.Identifier &&
553
- ['from', 'alloc', 'allocUnsafe'].includes(node.init.callee.property.name)) {
554
- bufferVars.add(varName);
555
- }
556
-
557
- // Check if assigned a buffer method result
558
- if (node.init.type === AST_NODE_TYPES.CallExpression) {
559
- const callee = node.init.callee;
560
- if (callee.type === AST_NODE_TYPES.MemberExpression &&
561
- callee.property.type === AST_NODE_TYPES.Identifier &&
562
- bufferMethods.includes(callee.property.name)) {
563
- bufferVars.add(varName);
564
- }
565
- }
566
-
567
- // Check variable name patterns
568
- if (bufferTypes.some(type => varName.toLowerCase().includes(type.toLowerCase()))) {
569
- bufferVars.add(varName);
570
- }
571
- }
572
- },
573
-
574
- // Check member expressions (buffer[index], buffer.method())
575
- MemberExpression(node: TSESTree.MemberExpression) {
576
- // Check for buffer[index] access
577
- if (node.computed && node.object.type === AST_NODE_TYPES.Identifier) {
578
- const bufferName = node.object.name;
579
- const indexNode = node.property;
580
-
581
- if (isBufferType(bufferName)) {
582
- // Check for negative indices
583
- if (couldBeNegative(indexNode)) {
584
- context.report({
585
- node,
586
- messageId: 'negativeBufferIndex',
587
- data: {
588
- filePath: filename,
589
- line: String(node.loc?.start.line ?? 0),
590
- },
591
- });
592
- return;
593
- }
594
-
595
- // Check for user-controlled indices without validation
596
- if (isUserControlledIndex(indexNode) && !isIndexValidated(indexNode)) {
597
- // Check if there's a bounds check in scope
598
- if (!hasBoundsCheck(bufferName, indexNode)) {
599
- /* c8 ignore start -- safetyChecker.isSafe requires JSDoc annotations not testable via RuleTester */
600
- if (safetyChecker.isSafe(node, context)) {
601
- return;
602
- }
603
- /* c8 ignore stop */
604
-
605
- context.report({
606
- node,
607
- messageId: 'userControlledBufferIndex',
608
- data: {
609
- filePath: filename,
610
- line: String(node.loc?.start.line ?? 0),
611
- },
612
- });
613
- return;
614
- }
615
- }
616
-
617
- // Check if there's any bounds validation
618
- if (!hasBoundsCheck(bufferName, indexNode) && !isIndexValidated(indexNode)) {
619
- /* c8 ignore start -- safetyChecker.isSafe requires JSDoc annotations not testable via RuleTester */
620
- if (safetyChecker.isSafe(node, context)) {
621
- return;
622
- }
623
- /* c8 ignore stop */
624
-
625
- context.report({
626
- node,
627
- messageId: 'unsafeBufferAccess',
628
- data: {
629
- filePath: filename,
630
- line: String(node.loc?.start.line ?? 0),
631
- },
632
- });
633
- }
634
- }
635
- }
636
-
637
- // Check for buffer method calls that need bounds checking
638
- if (node.property.type === 'Identifier' &&
639
- bufferMethods.includes(node.property.name) &&
640
- node.object.type === 'Identifier' &&
641
- isBufferType(node.object.name)) {
642
-
643
- // This is a parent of a CallExpression, we'll check it there
644
- }
645
- },
646
-
647
- // Check buffer method calls
648
- CallExpression(node: TSESTree.CallExpression) {
649
- const callee = node.callee;
650
-
651
- // Check for buffer.slice() calls
652
- if (callee.type === 'MemberExpression' &&
653
- callee.property.type === 'Identifier' &&
654
- callee.property.name === 'slice' &&
655
- callee.object.type === 'Identifier' &&
656
- isBufferType(callee.object.name)) {
657
-
658
- const args = node.arguments;
659
-
660
- // Check slice arguments
661
- for (const arg of args) {
662
- if (isUserControlledIndex(arg) && !isIndexValidated(arg)) {
663
- /* c8 ignore start -- safetyChecker.isSafe requires JSDoc annotations not testable via RuleTester */
664
- if (safetyChecker.isSafe(node, context)) {
665
- continue;
666
- }
667
- /* c8 ignore stop */
668
-
669
- context.report({
670
- node: arg,
671
- messageId: 'unsafeBufferSlice',
672
- data: {
673
- filePath: filename,
674
- line: String(node.loc?.start.line ?? 0),
675
- },
676
- });
677
- }
678
- }
679
- }
680
-
681
- // Check for buffer read/write methods
682
- if (callee.type === AST_NODE_TYPES.MemberExpression &&
683
- callee.property.type === AST_NODE_TYPES.Identifier &&
684
- bufferMethods.includes(callee.property.name) &&
685
- callee.object.type === AST_NODE_TYPES.Identifier &&
686
- isBufferType(callee.object.name)) {
687
-
688
- const args = node.arguments;
689
-
690
- // Check offset/length arguments
691
- for (const arg of args) {
692
- if (isUserControlledIndex(arg) && !isIndexValidated(arg)) {
693
- /* c8 ignore start -- safetyChecker.isSafe requires JSDoc annotations not testable via RuleTester */
694
- if (safetyChecker.isSafe(node, context)) {
695
- continue;
696
- }
697
- /* c8 ignore stop */
698
-
699
- context.report({
700
- node: arg,
701
- messageId: 'missingBoundsCheck',
702
- data: {
703
- filePath: filename,
704
- line: String(node.loc?.start.line ?? 0),
705
- },
706
- });
707
- }
708
- }
709
- }
710
- },
711
-
712
- // Check binary expressions that might involve buffer operations
713
- BinaryExpression(node: TSESTree.BinaryExpression) {
714
- // Look for patterns like buffer.length - something that might indicate bounds checking
715
- const leftText = sourceCode.getText(node.left);
716
- const rightText = sourceCode.getText(node.right);
717
-
718
- if (leftText.includes('.length') || rightText.includes('.length')) {
719
- // This might be a bounds check - we could analyze this further
720
- }
721
- }
722
- };
723
- },
724
- });