eslint-plugin-secure-coding 2.3.2 → 2.3.3

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 (361) hide show
  1. package/README.md +1 -0
  2. package/package.json +3 -10
  3. package/src/index.ts +605 -0
  4. package/src/rules/__tests__/integration-demo.test.ts +290 -0
  5. package/src/rules/__tests__/integration-llm.test.ts +89 -0
  6. package/src/rules/database-injection/database-injection.test.ts +456 -0
  7. package/src/rules/database-injection/index.ts +488 -0
  8. package/src/rules/detect-child-process/detect-child-process.test.ts +207 -0
  9. package/src/rules/detect-child-process/index.ts +634 -0
  10. package/src/rules/detect-eval-with-expression/detect-eval-with-expression.test.ts +416 -0
  11. package/src/rules/detect-eval-with-expression/index.ts +463 -0
  12. package/src/rules/detect-mixed-content/detect-mixed-content.test.ts +28 -0
  13. package/src/rules/detect-mixed-content/index.ts +52 -0
  14. package/src/rules/detect-non-literal-fs-filename/detect-non-literal-fs-filename.test.ts +269 -0
  15. package/src/rules/detect-non-literal-fs-filename/index.ts +551 -0
  16. package/src/rules/detect-non-literal-regexp/detect-non-literal-regexp.test.ts +189 -0
  17. package/src/rules/detect-non-literal-regexp/index.ts +490 -0
  18. package/src/rules/detect-object-injection/detect-object-injection.test.ts +440 -0
  19. package/src/rules/detect-object-injection/index.ts +674 -0
  20. package/src/rules/detect-suspicious-dependencies/detect-suspicious-dependencies.test.ts +32 -0
  21. package/src/rules/detect-suspicious-dependencies/index.ts +84 -0
  22. package/src/rules/detect-weak-password-validation/detect-weak-password-validation.test.ts +31 -0
  23. package/src/rules/detect-weak-password-validation/index.ts +68 -0
  24. package/src/rules/no-allow-arbitrary-loads/index.ts +54 -0
  25. package/src/rules/no-allow-arbitrary-loads/no-allow-arbitrary-loads.test.ts +28 -0
  26. package/src/rules/no-arbitrary-file-access/index.ts +238 -0
  27. package/src/rules/no-arbitrary-file-access/no-arbitrary-file-access.test.ts +119 -0
  28. package/src/rules/no-buffer-overread/index.ts +724 -0
  29. package/src/rules/no-buffer-overread/no-buffer-overread.test.ts +313 -0
  30. package/src/rules/no-clickjacking/index.ts +481 -0
  31. package/src/rules/no-clickjacking/no-clickjacking.test.ts +253 -0
  32. package/src/rules/no-client-side-auth-logic/index.ts +81 -0
  33. package/src/rules/no-client-side-auth-logic/no-client-side-auth-logic.test.ts +33 -0
  34. package/src/rules/no-credentials-in-query-params/index.ts +69 -0
  35. package/src/rules/no-credentials-in-query-params/no-credentials-in-query-params.test.ts +33 -0
  36. package/src/rules/no-credentials-in-storage-api/index.ts +64 -0
  37. package/src/rules/no-credentials-in-storage-api/no-credentials-in-storage-api.test.ts +31 -0
  38. package/src/rules/no-data-in-temp-storage/index.ts +75 -0
  39. package/src/rules/no-data-in-temp-storage/no-data-in-temp-storage.test.ts +33 -0
  40. package/src/rules/no-debug-code-in-production/index.ts +59 -0
  41. package/src/rules/no-debug-code-in-production/no-debug-code-in-production.test.ts +26 -0
  42. package/src/rules/no-directive-injection/index.ts +551 -0
  43. package/src/rules/no-directive-injection/no-directive-injection.test.ts +305 -0
  44. package/src/rules/no-disabled-certificate-validation/index.ts +72 -0
  45. package/src/rules/no-disabled-certificate-validation/no-disabled-certificate-validation.test.ts +33 -0
  46. package/src/rules/no-document-cookie/index.ts +113 -0
  47. package/src/rules/no-document-cookie/no-document-cookie.test.ts +382 -0
  48. package/src/rules/no-dynamic-dependency-loading/index.ts +60 -0
  49. package/src/rules/no-dynamic-dependency-loading/no-dynamic-dependency-loading.test.ts +27 -0
  50. package/src/rules/no-electron-security-issues/index.ts +504 -0
  51. package/src/rules/no-electron-security-issues/no-electron-security-issues.test.ts +324 -0
  52. package/src/rules/no-exposed-debug-endpoints/index.ts +73 -0
  53. package/src/rules/no-exposed-debug-endpoints/no-exposed-debug-endpoints.test.ts +40 -0
  54. package/src/rules/no-exposed-sensitive-data/index.ts +428 -0
  55. package/src/rules/no-exposed-sensitive-data/no-exposed-sensitive-data.test.ts +75 -0
  56. package/src/rules/no-format-string-injection/index.ts +801 -0
  57. package/src/rules/no-format-string-injection/no-format-string-injection.test.ts +437 -0
  58. package/src/rules/no-graphql-injection/index.ts +508 -0
  59. package/src/rules/no-graphql-injection/no-graphql-injection.test.ts +371 -0
  60. package/src/rules/no-hardcoded-credentials/index.ts +478 -0
  61. package/src/rules/no-hardcoded-credentials/no-hardcoded-credentials.test.ts +639 -0
  62. package/src/rules/no-hardcoded-session-tokens/index.ts +69 -0
  63. package/src/rules/no-hardcoded-session-tokens/no-hardcoded-session-tokens.test.ts +42 -0
  64. package/src/rules/no-http-urls/index.ts +131 -0
  65. package/src/rules/no-http-urls/no-http-urls.test.ts +60 -0
  66. package/src/rules/no-improper-sanitization/index.ts +502 -0
  67. package/src/rules/no-improper-sanitization/no-improper-sanitization.test.ts +156 -0
  68. package/src/rules/no-improper-type-validation/index.ts +572 -0
  69. package/src/rules/no-improper-type-validation/no-improper-type-validation.test.ts +372 -0
  70. package/src/rules/no-insecure-comparison/index.ts +232 -0
  71. package/src/rules/no-insecure-comparison/no-insecure-comparison.test.ts +218 -0
  72. package/src/rules/no-insecure-cookie-settings/index.ts +391 -0
  73. package/src/rules/no-insecure-cookie-settings/no-insecure-cookie-settings.test.ts +409 -0
  74. package/src/rules/no-insecure-jwt/index.ts +467 -0
  75. package/src/rules/no-insecure-jwt/no-insecure-jwt.test.ts +259 -0
  76. package/src/rules/no-insecure-redirects/index.ts +267 -0
  77. package/src/rules/no-insecure-redirects/no-insecure-redirects.test.ts +108 -0
  78. package/src/rules/no-insecure-websocket/index.ts +72 -0
  79. package/src/rules/no-insecure-websocket/no-insecure-websocket.test.ts +42 -0
  80. package/src/rules/no-insufficient-postmessage-validation/index.ts +497 -0
  81. package/src/rules/no-insufficient-postmessage-validation/no-insufficient-postmessage-validation.test.ts +360 -0
  82. package/src/rules/no-insufficient-random/index.ts +288 -0
  83. package/src/rules/no-insufficient-random/no-insufficient-random.test.ts +246 -0
  84. package/src/rules/no-ldap-injection/index.ts +547 -0
  85. package/src/rules/no-ldap-injection/no-ldap-injection.test.ts +317 -0
  86. package/src/rules/no-missing-authentication/index.ts +408 -0
  87. package/src/rules/no-missing-authentication/no-missing-authentication.test.ts +350 -0
  88. package/src/rules/no-missing-cors-check/index.ts +453 -0
  89. package/src/rules/no-missing-cors-check/no-missing-cors-check.test.ts +392 -0
  90. package/src/rules/no-missing-csrf-protection/index.ts +229 -0
  91. package/src/rules/no-missing-csrf-protection/no-missing-csrf-protection.test.ts +222 -0
  92. package/src/rules/no-missing-security-headers/index.ts +266 -0
  93. package/src/rules/no-missing-security-headers/no-missing-security-headers.test.ts +98 -0
  94. package/src/rules/no-password-in-url/index.ts +64 -0
  95. package/src/rules/no-password-in-url/no-password-in-url.test.ts +27 -0
  96. package/src/rules/no-permissive-cors/index.ts +78 -0
  97. package/src/rules/no-permissive-cors/no-permissive-cors.test.ts +28 -0
  98. package/src/rules/no-pii-in-logs/index.ts +83 -0
  99. package/src/rules/no-pii-in-logs/no-pii-in-logs.test.ts +26 -0
  100. package/src/rules/no-postmessage-origin-wildcard/index.ts +67 -0
  101. package/src/rules/no-postmessage-origin-wildcard/no-postmessage-origin-wildcard.test.ts +27 -0
  102. package/src/rules/no-privilege-escalation/index.ts +403 -0
  103. package/src/rules/no-privilege-escalation/no-privilege-escalation.test.ts +306 -0
  104. package/src/rules/no-redos-vulnerable-regex/index.ts +379 -0
  105. package/src/rules/no-redos-vulnerable-regex/no-redos-vulnerable-regex.test.ts +83 -0
  106. package/src/rules/no-sensitive-data-exposure/index.ts +294 -0
  107. package/src/rules/no-sensitive-data-exposure/no-sensitive-data-exposure.test.ts +262 -0
  108. package/src/rules/no-sensitive-data-in-analytics/index.ts +73 -0
  109. package/src/rules/no-sensitive-data-in-analytics/no-sensitive-data-in-analytics.test.ts +42 -0
  110. package/src/rules/no-sensitive-data-in-cache/index.ts +59 -0
  111. package/src/rules/no-sensitive-data-in-cache/no-sensitive-data-in-cache.test.ts +32 -0
  112. package/src/rules/no-sql-injection/index.ts +424 -0
  113. package/src/rules/no-sql-injection/no-sql-injection.test.ts +303 -0
  114. package/src/rules/no-timing-attack/index.ts +552 -0
  115. package/src/rules/no-timing-attack/no-timing-attack.test.ts +348 -0
  116. package/src/rules/no-toctou-vulnerability/index.ts +250 -0
  117. package/src/rules/no-toctou-vulnerability/no-toctou-vulnerability.test.ts +60 -0
  118. package/src/rules/no-tracking-without-consent/index.ts +78 -0
  119. package/src/rules/no-tracking-without-consent/no-tracking-without-consent.test.ts +34 -0
  120. package/src/rules/no-unchecked-loop-condition/index.ts +781 -0
  121. package/src/rules/no-unchecked-loop-condition/no-unchecked-loop-condition.test.ts +459 -0
  122. package/src/rules/no-unencrypted-local-storage/index.ts +73 -0
  123. package/src/rules/no-unencrypted-local-storage/no-unencrypted-local-storage.test.ts +41 -0
  124. package/src/rules/no-unencrypted-transmission/index.ts +296 -0
  125. package/src/rules/no-unencrypted-transmission/no-unencrypted-transmission.test.ts +287 -0
  126. package/src/rules/no-unescaped-url-parameter/index.ts +424 -0
  127. package/src/rules/no-unescaped-url-parameter/no-unescaped-url-parameter.test.ts +263 -0
  128. package/src/rules/no-unlimited-resource-allocation/index.ts +767 -0
  129. package/src/rules/no-unlimited-resource-allocation/no-unlimited-resource-allocation.test.ts +544 -0
  130. package/src/rules/no-unsafe-deserialization/index.ts +593 -0
  131. package/src/rules/no-unsafe-deserialization/no-unsafe-deserialization.test.ts +310 -0
  132. package/src/rules/no-unsafe-dynamic-require/index.ts +125 -0
  133. package/src/rules/no-unsafe-dynamic-require/no-unsafe-dynamic-require.test.ts +151 -0
  134. package/src/rules/no-unsafe-regex-construction/index.ts +370 -0
  135. package/src/rules/no-unsafe-regex-construction/no-unsafe-regex-construction.test.ts +181 -0
  136. package/src/rules/no-unsanitized-html/index.ts +400 -0
  137. package/src/rules/no-unsanitized-html/no-unsanitized-html.test.ts +488 -0
  138. package/src/rules/no-unvalidated-deeplinks/index.ts +73 -0
  139. package/src/rules/no-unvalidated-deeplinks/no-unvalidated-deeplinks.test.ts +29 -0
  140. package/src/rules/no-unvalidated-user-input/index.ts +498 -0
  141. package/src/rules/no-unvalidated-user-input/no-unvalidated-user-input.test.ts +463 -0
  142. package/src/rules/no-verbose-error-messages/index.ts +83 -0
  143. package/src/rules/no-verbose-error-messages/no-verbose-error-messages.test.ts +34 -0
  144. package/src/rules/no-weak-crypto/index.ts +447 -0
  145. package/src/rules/no-weak-crypto/no-weak-crypto.test.ts +297 -0
  146. package/src/rules/no-weak-password-recovery/index.ts +509 -0
  147. package/src/rules/no-weak-password-recovery/no-weak-password-recovery.test.ts +184 -0
  148. package/src/rules/no-xpath-injection/index.ts +596 -0
  149. package/src/rules/no-xpath-injection/no-xpath-injection.test.ts +405 -0
  150. package/src/rules/no-xxe-injection/index.ts +342 -0
  151. package/src/rules/no-xxe-injection/no-xxe-injection.test.ts +122 -0
  152. package/src/rules/no-zip-slip/index.ts +526 -0
  153. package/src/rules/no-zip-slip/no-zip-slip.test.ts +305 -0
  154. package/src/rules/require-backend-authorization/index.ts +71 -0
  155. package/src/rules/require-backend-authorization/require-backend-authorization.test.ts +31 -0
  156. package/src/rules/require-code-minification/index.ts +54 -0
  157. package/src/rules/require-code-minification/require-code-minification.test.ts +30 -0
  158. package/src/rules/require-csp-headers/index.ts +74 -0
  159. package/src/rules/require-csp-headers/require-csp-headers.test.ts +34 -0
  160. package/src/rules/require-data-minimization/index.ts +65 -0
  161. package/src/rules/require-data-minimization/require-data-minimization.test.ts +31 -0
  162. package/src/rules/require-dependency-integrity/index.ts +78 -0
  163. package/src/rules/require-dependency-integrity/require-dependency-integrity.test.ts +44 -0
  164. package/src/rules/require-https-only/index.ts +75 -0
  165. package/src/rules/require-https-only/require-https-only.test.ts +26 -0
  166. package/src/rules/require-mime-type-validation/index.ts +77 -0
  167. package/src/rules/require-mime-type-validation/require-mime-type-validation.test.ts +32 -0
  168. package/src/rules/require-network-timeout/index.ts +58 -0
  169. package/src/rules/require-network-timeout/require-network-timeout.test.ts +26 -0
  170. package/src/rules/require-package-lock/index.ts +75 -0
  171. package/src/rules/require-package-lock/require-package-lock.test.ts +27 -0
  172. package/src/rules/require-secure-credential-storage/index.ts +60 -0
  173. package/src/rules/require-secure-credential-storage/require-secure-credential-storage.test.ts +26 -0
  174. package/src/rules/require-secure-defaults/index.ts +54 -0
  175. package/src/rules/require-secure-defaults/require-secure-defaults.test.ts +26 -0
  176. package/src/rules/require-secure-deletion/index.ts +52 -0
  177. package/src/rules/require-secure-deletion/require-secure-deletion.test.ts +29 -0
  178. package/src/rules/require-storage-encryption/index.ts +60 -0
  179. package/src/rules/require-storage-encryption/require-storage-encryption.test.ts +26 -0
  180. package/src/rules/require-url-validation/index.ts +85 -0
  181. package/src/rules/require-url-validation/require-url-validation.test.ts +32 -0
  182. package/src/types/{index.d.ts → index.ts} +157 -53
  183. package/src/index.d.ts +0 -32
  184. package/src/index.js +0 -465
  185. package/src/rules/database-injection/index.d.ts +0 -13
  186. package/src/rules/database-injection/index.js +0 -406
  187. package/src/rules/detect-child-process/index.d.ts +0 -11
  188. package/src/rules/detect-child-process/index.js +0 -529
  189. package/src/rules/detect-eval-with-expression/index.d.ts +0 -9
  190. package/src/rules/detect-eval-with-expression/index.js +0 -392
  191. package/src/rules/detect-mixed-content/index.d.ts +0 -8
  192. package/src/rules/detect-mixed-content/index.js +0 -44
  193. package/src/rules/detect-non-literal-fs-filename/index.d.ts +0 -7
  194. package/src/rules/detect-non-literal-fs-filename/index.js +0 -454
  195. package/src/rules/detect-non-literal-regexp/index.d.ts +0 -9
  196. package/src/rules/detect-non-literal-regexp/index.js +0 -403
  197. package/src/rules/detect-object-injection/index.d.ts +0 -11
  198. package/src/rules/detect-object-injection/index.js +0 -560
  199. package/src/rules/detect-suspicious-dependencies/index.d.ts +0 -8
  200. package/src/rules/detect-suspicious-dependencies/index.js +0 -71
  201. package/src/rules/detect-weak-password-validation/index.d.ts +0 -6
  202. package/src/rules/detect-weak-password-validation/index.js +0 -58
  203. package/src/rules/no-allow-arbitrary-loads/index.d.ts +0 -8
  204. package/src/rules/no-allow-arbitrary-loads/index.js +0 -47
  205. package/src/rules/no-arbitrary-file-access/index.d.ts +0 -13
  206. package/src/rules/no-arbitrary-file-access/index.js +0 -195
  207. package/src/rules/no-buffer-overread/index.d.ts +0 -29
  208. package/src/rules/no-buffer-overread/index.js +0 -606
  209. package/src/rules/no-clickjacking/index.d.ts +0 -10
  210. package/src/rules/no-clickjacking/index.js +0 -396
  211. package/src/rules/no-client-side-auth-logic/index.d.ts +0 -6
  212. package/src/rules/no-client-side-auth-logic/index.js +0 -69
  213. package/src/rules/no-credentials-in-query-params/index.d.ts +0 -8
  214. package/src/rules/no-credentials-in-query-params/index.js +0 -57
  215. package/src/rules/no-credentials-in-storage-api/index.d.ts +0 -6
  216. package/src/rules/no-credentials-in-storage-api/index.js +0 -54
  217. package/src/rules/no-data-in-temp-storage/index.d.ts +0 -6
  218. package/src/rules/no-data-in-temp-storage/index.js +0 -64
  219. package/src/rules/no-debug-code-in-production/index.d.ts +0 -8
  220. package/src/rules/no-debug-code-in-production/index.js +0 -51
  221. package/src/rules/no-directive-injection/index.d.ts +0 -12
  222. package/src/rules/no-directive-injection/index.js +0 -457
  223. package/src/rules/no-disabled-certificate-validation/index.d.ts +0 -6
  224. package/src/rules/no-disabled-certificate-validation/index.js +0 -61
  225. package/src/rules/no-document-cookie/index.d.ts +0 -5
  226. package/src/rules/no-document-cookie/index.js +0 -89
  227. package/src/rules/no-dynamic-dependency-loading/index.d.ts +0 -8
  228. package/src/rules/no-dynamic-dependency-loading/index.js +0 -51
  229. package/src/rules/no-electron-security-issues/index.d.ts +0 -10
  230. package/src/rules/no-electron-security-issues/index.js +0 -423
  231. package/src/rules/no-exposed-debug-endpoints/index.d.ts +0 -6
  232. package/src/rules/no-exposed-debug-endpoints/index.js +0 -62
  233. package/src/rules/no-exposed-sensitive-data/index.d.ts +0 -11
  234. package/src/rules/no-exposed-sensitive-data/index.js +0 -340
  235. package/src/rules/no-format-string-injection/index.d.ts +0 -17
  236. package/src/rules/no-format-string-injection/index.js +0 -660
  237. package/src/rules/no-graphql-injection/index.d.ts +0 -12
  238. package/src/rules/no-graphql-injection/index.js +0 -411
  239. package/src/rules/no-hardcoded-credentials/index.d.ts +0 -26
  240. package/src/rules/no-hardcoded-credentials/index.js +0 -376
  241. package/src/rules/no-hardcoded-session-tokens/index.d.ts +0 -6
  242. package/src/rules/no-hardcoded-session-tokens/index.js +0 -59
  243. package/src/rules/no-http-urls/index.d.ts +0 -12
  244. package/src/rules/no-http-urls/index.js +0 -114
  245. package/src/rules/no-improper-sanitization/index.d.ts +0 -12
  246. package/src/rules/no-improper-sanitization/index.js +0 -411
  247. package/src/rules/no-improper-type-validation/index.d.ts +0 -10
  248. package/src/rules/no-improper-type-validation/index.js +0 -475
  249. package/src/rules/no-insecure-comparison/index.d.ts +0 -7
  250. package/src/rules/no-insecure-comparison/index.js +0 -193
  251. package/src/rules/no-insecure-cookie-settings/index.d.ts +0 -9
  252. package/src/rules/no-insecure-cookie-settings/index.js +0 -306
  253. package/src/rules/no-insecure-jwt/index.d.ts +0 -10
  254. package/src/rules/no-insecure-jwt/index.js +0 -380
  255. package/src/rules/no-insecure-redirects/index.d.ts +0 -7
  256. package/src/rules/no-insecure-redirects/index.js +0 -216
  257. package/src/rules/no-insecure-websocket/index.d.ts +0 -6
  258. package/src/rules/no-insecure-websocket/index.js +0 -61
  259. package/src/rules/no-insufficient-postmessage-validation/index.d.ts +0 -14
  260. package/src/rules/no-insufficient-postmessage-validation/index.js +0 -392
  261. package/src/rules/no-insufficient-random/index.d.ts +0 -9
  262. package/src/rules/no-insufficient-random/index.js +0 -208
  263. package/src/rules/no-ldap-injection/index.d.ts +0 -10
  264. package/src/rules/no-ldap-injection/index.js +0 -455
  265. package/src/rules/no-missing-authentication/index.d.ts +0 -13
  266. package/src/rules/no-missing-authentication/index.js +0 -333
  267. package/src/rules/no-missing-cors-check/index.d.ts +0 -9
  268. package/src/rules/no-missing-cors-check/index.js +0 -399
  269. package/src/rules/no-missing-csrf-protection/index.d.ts +0 -11
  270. package/src/rules/no-missing-csrf-protection/index.js +0 -180
  271. package/src/rules/no-missing-security-headers/index.d.ts +0 -7
  272. package/src/rules/no-missing-security-headers/index.js +0 -218
  273. package/src/rules/no-password-in-url/index.d.ts +0 -8
  274. package/src/rules/no-password-in-url/index.js +0 -54
  275. package/src/rules/no-permissive-cors/index.d.ts +0 -8
  276. package/src/rules/no-permissive-cors/index.js +0 -65
  277. package/src/rules/no-pii-in-logs/index.d.ts +0 -8
  278. package/src/rules/no-pii-in-logs/index.js +0 -70
  279. package/src/rules/no-postmessage-origin-wildcard/index.d.ts +0 -8
  280. package/src/rules/no-postmessage-origin-wildcard/index.js +0 -56
  281. package/src/rules/no-privilege-escalation/index.d.ts +0 -13
  282. package/src/rules/no-privilege-escalation/index.js +0 -321
  283. package/src/rules/no-redos-vulnerable-regex/index.d.ts +0 -7
  284. package/src/rules/no-redos-vulnerable-regex/index.js +0 -306
  285. package/src/rules/no-sensitive-data-exposure/index.d.ts +0 -11
  286. package/src/rules/no-sensitive-data-exposure/index.js +0 -250
  287. package/src/rules/no-sensitive-data-in-analytics/index.d.ts +0 -8
  288. package/src/rules/no-sensitive-data-in-analytics/index.js +0 -62
  289. package/src/rules/no-sensitive-data-in-cache/index.d.ts +0 -8
  290. package/src/rules/no-sensitive-data-in-cache/index.js +0 -52
  291. package/src/rules/no-sql-injection/index.d.ts +0 -10
  292. package/src/rules/no-sql-injection/index.js +0 -335
  293. package/src/rules/no-timing-attack/index.d.ts +0 -10
  294. package/src/rules/no-timing-attack/index.js +0 -447
  295. package/src/rules/no-toctou-vulnerability/index.d.ts +0 -7
  296. package/src/rules/no-toctou-vulnerability/index.js +0 -208
  297. package/src/rules/no-tracking-without-consent/index.d.ts +0 -6
  298. package/src/rules/no-tracking-without-consent/index.js +0 -67
  299. package/src/rules/no-unchecked-loop-condition/index.d.ts +0 -12
  300. package/src/rules/no-unchecked-loop-condition/index.js +0 -646
  301. package/src/rules/no-unencrypted-local-storage/index.d.ts +0 -8
  302. package/src/rules/no-unencrypted-local-storage/index.js +0 -61
  303. package/src/rules/no-unencrypted-transmission/index.d.ts +0 -11
  304. package/src/rules/no-unencrypted-transmission/index.js +0 -236
  305. package/src/rules/no-unescaped-url-parameter/index.d.ts +0 -9
  306. package/src/rules/no-unescaped-url-parameter/index.js +0 -355
  307. package/src/rules/no-unlimited-resource-allocation/index.d.ts +0 -12
  308. package/src/rules/no-unlimited-resource-allocation/index.js +0 -643
  309. package/src/rules/no-unsafe-deserialization/index.d.ts +0 -10
  310. package/src/rules/no-unsafe-deserialization/index.js +0 -491
  311. package/src/rules/no-unsafe-dynamic-require/index.d.ts +0 -5
  312. package/src/rules/no-unsafe-dynamic-require/index.js +0 -106
  313. package/src/rules/no-unsafe-regex-construction/index.d.ts +0 -9
  314. package/src/rules/no-unsafe-regex-construction/index.js +0 -291
  315. package/src/rules/no-unsanitized-html/index.d.ts +0 -9
  316. package/src/rules/no-unsanitized-html/index.js +0 -335
  317. package/src/rules/no-unvalidated-deeplinks/index.d.ts +0 -6
  318. package/src/rules/no-unvalidated-deeplinks/index.js +0 -62
  319. package/src/rules/no-unvalidated-user-input/index.d.ts +0 -9
  320. package/src/rules/no-unvalidated-user-input/index.js +0 -420
  321. package/src/rules/no-verbose-error-messages/index.d.ts +0 -8
  322. package/src/rules/no-verbose-error-messages/index.js +0 -68
  323. package/src/rules/no-weak-crypto/index.d.ts +0 -11
  324. package/src/rules/no-weak-crypto/index.js +0 -351
  325. package/src/rules/no-weak-password-recovery/index.d.ts +0 -12
  326. package/src/rules/no-weak-password-recovery/index.js +0 -424
  327. package/src/rules/no-xpath-injection/index.d.ts +0 -10
  328. package/src/rules/no-xpath-injection/index.js +0 -487
  329. package/src/rules/no-xxe-injection/index.d.ts +0 -7
  330. package/src/rules/no-xxe-injection/index.js +0 -266
  331. package/src/rules/no-zip-slip/index.d.ts +0 -9
  332. package/src/rules/no-zip-slip/index.js +0 -445
  333. package/src/rules/require-backend-authorization/index.d.ts +0 -6
  334. package/src/rules/require-backend-authorization/index.js +0 -60
  335. package/src/rules/require-code-minification/index.d.ts +0 -8
  336. package/src/rules/require-code-minification/index.js +0 -47
  337. package/src/rules/require-csp-headers/index.d.ts +0 -6
  338. package/src/rules/require-csp-headers/index.js +0 -64
  339. package/src/rules/require-data-minimization/index.d.ts +0 -8
  340. package/src/rules/require-data-minimization/index.js +0 -53
  341. package/src/rules/require-dependency-integrity/index.d.ts +0 -6
  342. package/src/rules/require-dependency-integrity/index.js +0 -64
  343. package/src/rules/require-https-only/index.d.ts +0 -8
  344. package/src/rules/require-https-only/index.js +0 -62
  345. package/src/rules/require-mime-type-validation/index.d.ts +0 -6
  346. package/src/rules/require-mime-type-validation/index.js +0 -66
  347. package/src/rules/require-network-timeout/index.d.ts +0 -8
  348. package/src/rules/require-network-timeout/index.js +0 -50
  349. package/src/rules/require-package-lock/index.d.ts +0 -8
  350. package/src/rules/require-package-lock/index.js +0 -63
  351. package/src/rules/require-secure-credential-storage/index.d.ts +0 -8
  352. package/src/rules/require-secure-credential-storage/index.js +0 -50
  353. package/src/rules/require-secure-defaults/index.d.ts +0 -8
  354. package/src/rules/require-secure-defaults/index.js +0 -47
  355. package/src/rules/require-secure-deletion/index.d.ts +0 -8
  356. package/src/rules/require-secure-deletion/index.js +0 -44
  357. package/src/rules/require-storage-encryption/index.d.ts +0 -8
  358. package/src/rules/require-storage-encryption/index.js +0 -50
  359. package/src/rules/require-url-validation/index.d.ts +0 -6
  360. package/src/rules/require-url-validation/index.js +0 -72
  361. package/src/types/index.js +0 -17
@@ -0,0 +1,348 @@
1
+ /**
2
+ * Comprehensive tests for no-timing-attack rule
3
+ * Security: CWE-208 (Timing Attack)
4
+ */
5
+ import { RuleTester } from '@typescript-eslint/rule-tester';
6
+ import { describe, it, afterAll } from 'vitest';
7
+ import parser from '@typescript-eslint/parser';
8
+ import { noTimingAttack } from './index';
9
+
10
+ // Configure RuleTester for Vitest
11
+ RuleTester.afterAll = afterAll;
12
+ RuleTester.it = it;
13
+ RuleTester.itOnly = it.only;
14
+ RuleTester.describe = describe;
15
+
16
+ // Use Flat Config format (ESLint 9+)
17
+ const ruleTester = new RuleTester({
18
+ languageOptions: {
19
+ parser,
20
+ ecmaVersion: 2022,
21
+ sourceType: 'module',
22
+ },
23
+ });
24
+
25
+ describe('no-timing-attack', () => {
26
+ describe('Valid Code', () => {
27
+ ruleTester.run('valid - secure timing practices', noTimingAttack, {
28
+ valid: [
29
+ // Timing-safe comparisons
30
+ {
31
+ code: 'crypto.timingSafeEqual(Buffer.from(a), Buffer.from(b));',
32
+ },
33
+ // Non-sensitive comparisons
34
+ {
35
+ code: 'if (user.name === "admin") return true;',
36
+ },
37
+ // Safe early returns in non-auth contexts
38
+ {
39
+ code: `
40
+ function validateEmail(email) {
41
+ if (!email) return false;
42
+ return email.includes('@');
43
+ }
44
+ `,
45
+ },
46
+ // Non-auth function with includes() check - should NOT be flagged
47
+ {
48
+ code: `
49
+ const VALID_KEYS = ['name', 'email', 'age'];
50
+ function getField(obj, key) {
51
+ if (VALID_KEYS.includes(key)) {
52
+ return obj[key];
53
+ }
54
+ }
55
+ `,
56
+ },
57
+ // Non-auth function with hasOwnProperty check - should NOT be flagged
58
+ {
59
+ code: `
60
+ function safeGet(obj, key) {
61
+ if (Object.prototype.hasOwnProperty.call(obj, key)) {
62
+ return obj[key];
63
+ }
64
+ }
65
+ `,
66
+ },
67
+ // Timing-safe libraries
68
+ {
69
+ code: 'const bcrypt = require("bcrypt"); bcrypt.compare(password, hash);',
70
+ },
71
+ ],
72
+ invalid: [],
73
+ });
74
+ });
75
+
76
+ describe('Invalid Code - Insecure Comparisons', () => {
77
+ ruleTester.run('invalid - insecure string comparisons', noTimingAttack, {
78
+ valid: [],
79
+ invalid: [
80
+ {
81
+ code: 'if (userInput === storedPassword) authenticate();',
82
+ errors: [
83
+ {
84
+ messageId: 'insecureStringComparison',
85
+ },
86
+ ],
87
+ },
88
+ {
89
+ code: 'if (token == storedToken) return true;',
90
+ errors: [
91
+ {
92
+ messageId: 'insecureStringComparison',
93
+ },
94
+ ],
95
+ },
96
+ {
97
+ code: 'const isValid = providedSecret === actualSecret;',
98
+ errors: [
99
+ {
100
+ messageId: 'insecureStringComparison',
101
+ },
102
+ ],
103
+ },
104
+ {
105
+ code: `
106
+ if (providedSecret === actualSecret) {
107
+ return true;
108
+ }
109
+ `,
110
+ options: [{ allowEarlyReturns: true }],
111
+ errors: [
112
+ {
113
+ messageId: 'insecureStringComparison',
114
+ },
115
+ ],
116
+ },
117
+ ],
118
+ });
119
+ });
120
+
121
+ describe('Invalid Code - Early Return Leakage', () => {
122
+ ruleTester.run('invalid - early returns in auth functions', noTimingAttack, {
123
+ valid: [],
124
+ invalid: [
125
+ {
126
+ code: `
127
+ function authenticate(password) {
128
+ if (!password) return false;
129
+ return checkPassword(password);
130
+ }
131
+ `,
132
+ errors: [
133
+ {
134
+ messageId: 'earlyReturnLeakage',
135
+ },
136
+ ],
137
+ },
138
+ {
139
+ code: `
140
+ function verifyToken(token) {
141
+ if (!token) return false;
142
+ return validateToken(token);
143
+ }
144
+ `,
145
+ errors: [
146
+ {
147
+ messageId: 'earlyReturnLeakage',
148
+ },
149
+ ],
150
+ },
151
+ {
152
+ code: `
153
+ function login(credentials) {
154
+ if (!credentials.password) return false;
155
+ return authenticateUser(credentials);
156
+ }
157
+ `,
158
+ errors: [
159
+ {
160
+ messageId: 'earlyReturnLeakage',
161
+ },
162
+ ],
163
+ },
164
+ ],
165
+ });
166
+ });
167
+
168
+ describe('Invalid Code - Timing Attacks', () => {
169
+ ruleTester.run('invalid - timing-sensitive operations', noTimingAttack, {
170
+ valid: [],
171
+ invalid: [
172
+ {
173
+ code: 'someObject.equals(userInput, storedSecret);',
174
+ errors: [
175
+ {
176
+ messageId: 'timingAttack',
177
+ },
178
+ ],
179
+ },
180
+ {
181
+ code: 'password.compare(inputPassword);',
182
+ errors: [
183
+ {
184
+ messageId: 'timingAttack',
185
+ },
186
+ ],
187
+ },
188
+ ],
189
+ });
190
+ });
191
+
192
+ describe('Valid Code - False Positives Reduced', () => {
193
+ ruleTester.run('valid - false positives reduced', noTimingAttack, {
194
+ valid: [
195
+ // Safe annotations
196
+ {
197
+ code: `
198
+ /** @timing-safe */
199
+ if (userInput === storedPassword) authenticate();
200
+ `,
201
+ },
202
+ // Sanitized inputs
203
+ {
204
+ code: `
205
+ const cleanInput = sanitize(userInput);
206
+ if (cleanInput === storedPassword) authenticate();
207
+ `,
208
+ },
209
+ // Non-sensitive data
210
+ {
211
+ code: `
212
+ const user = { name: 'john' };
213
+ if (user.name === 'admin') return true;
214
+ `,
215
+ },
216
+ // Early returns allowed in config
217
+ {
218
+ code: `
219
+ function authenticate(password) {
220
+ if (!password) return false;
221
+ return checkPassword(password);
222
+ }
223
+ `,
224
+ options: [{ allowEarlyReturns: true }],
225
+ },
226
+ ],
227
+ invalid: [],
228
+ });
229
+ });
230
+
231
+ describe('Configuration Options', () => {
232
+ ruleTester.run('config - custom auth functions', noTimingAttack, {
233
+ valid: [
234
+ // No valid cases - configured auth functions still get checked
235
+ ],
236
+ invalid: [
237
+ {
238
+ code: `
239
+ function myAuth(password) {
240
+ if (!password) return false;
241
+ return true;
242
+ }
243
+ `,
244
+ options: [{ authFunctions: ['myAuth'] }],
245
+ errors: [
246
+ {
247
+ messageId: 'earlyReturnLeakage',
248
+ },
249
+ ],
250
+ },
251
+ {
252
+ code: `
253
+ function myAuth(password) {
254
+ if (!password) return false;
255
+ return true;
256
+ }
257
+ `,
258
+ options: [{ authFunctions: ['differentAuth'] }],
259
+ errors: [
260
+ {
261
+ messageId: 'earlyReturnLeakage',
262
+ },
263
+ ],
264
+ },
265
+ ],
266
+ });
267
+
268
+ ruleTester.run('config - custom sensitive variables', noTimingAttack, {
269
+ valid: [
270
+ // Valid cases would be comparisons that don't involve sensitive data
271
+ {
272
+ code: 'if (normalVar === otherVar) return true;',
273
+ options: [{ sensitiveVariables: ['customToken'] }],
274
+ },
275
+ ],
276
+ invalid: [
277
+ {
278
+ code: 'if (mySecret === otherSecret) return true;',
279
+ options: [{ sensitiveVariables: ['mySecret'] }],
280
+ errors: [
281
+ {
282
+ messageId: 'insecureStringComparison',
283
+ },
284
+ ],
285
+ },
286
+ {
287
+ code: 'if (customToken === storedToken) return true;',
288
+ options: [{ sensitiveVariables: ['customToken'] }],
289
+ errors: [
290
+ {
291
+ messageId: 'insecureStringComparison',
292
+ },
293
+ ],
294
+ },
295
+ ],
296
+ });
297
+ });
298
+
299
+ describe('Complex Authentication Scenarios', () => {
300
+ ruleTester.run('complex - authentication functions', noTimingAttack, {
301
+ valid: [],
302
+ invalid: [
303
+ {
304
+ code: `
305
+ function login(username, password) {
306
+ const user = findUser(username);
307
+ if (!user) return false; // Timing leak!
308
+
309
+ if (user.password === password) {
310
+ return true;
311
+ }
312
+ return false;
313
+ }
314
+ `,
315
+ errors: [
316
+ {
317
+ messageId: 'earlyReturnLeakage',
318
+ },
319
+ {
320
+ messageId: 'insecureStringComparison',
321
+ },
322
+ {
323
+ messageId: 'earlyReturnLeakage',
324
+ },
325
+ ],
326
+ },
327
+ {
328
+ code: `
329
+ function verifyToken(token) {
330
+ if (!token || token.length < 10) return false; // Timing leak!
331
+
332
+ const storedToken = getStoredToken();
333
+ return token === storedToken; // Insecure comparison
334
+ }
335
+ `,
336
+ errors: [
337
+ {
338
+ messageId: 'earlyReturnLeakage',
339
+ },
340
+ {
341
+ messageId: 'insecureStringComparison',
342
+ },
343
+ ],
344
+ },
345
+ ],
346
+ });
347
+ });
348
+ });
@@ -0,0 +1,250 @@
1
+ /**
2
+ * ESLint Rule: no-toctou-vulnerability
3
+ * Detects Time-of-Check-Time-of-Use vulnerabilities
4
+ * CWE-367: Time-of-check Time-of-use (TOCTOU) Race Condition
5
+ *
6
+ * @see https://cwe.mitre.org/data/definitions/367.html
7
+ * @see https://owasp.org/www-community/vulnerabilities/TOCTOU_Race_Condition
8
+ */
9
+ import type { TSESLint, TSESTree } from '@interlace/eslint-devkit';
10
+ import { formatLLMMessage, MessageIcons } from '@interlace/eslint-devkit';
11
+ import { createRule } from '@interlace/eslint-devkit';
12
+
13
+ type MessageIds =
14
+ | 'toctouVulnerability'
15
+ | 'useAtomicOperations'
16
+ | 'useFsPromises'
17
+ | 'addProperLocking';
18
+
19
+ export interface Options {
20
+ /** Ignore in test files. Default: true */
21
+ ignoreInTests?: boolean;
22
+
23
+ /** File system methods to check. Default: ['fs.existsSync', 'fs.statSync', 'fs.accessSync'] */
24
+ fsMethods?: string[];
25
+ }
26
+
27
+ type RuleOptions = [Options?];
28
+
29
+ export const noToctouVulnerability = createRule<RuleOptions, MessageIds>({
30
+ name: 'no-toctou-vulnerability',
31
+ meta: {
32
+ type: 'problem',
33
+ docs: {
34
+ description: 'Detects Time-of-Check-Time-of-Use vulnerabilities',
35
+ },
36
+ hasSuggestions: true,
37
+ messages: {
38
+ toctouVulnerability: formatLLMMessage({
39
+ icon: MessageIcons.SECURITY,
40
+ issueName: 'TOCTOU vulnerability',
41
+ cwe: 'CWE-367',
42
+ description: 'Time-of-check Time-of-use race condition detected',
43
+ severity: 'HIGH',
44
+ fix: 'Use atomic operations or fs.promises for file operations',
45
+ documentationLink: 'https://cwe.mitre.org/data/definitions/367.html',
46
+ }),
47
+ useAtomicOperations: formatLLMMessage({
48
+ icon: MessageIcons.INFO,
49
+ issueName: 'Use Atomic Operations',
50
+ description: 'Use atomic file operations',
51
+ severity: 'LOW',
52
+ fix: 'fs.promises.access() then fs.promises.readFile()',
53
+ documentationLink: 'https://nodejs.org/api/fs.html#fspromisesaccesspath-mode',
54
+ }),
55
+ useFsPromises: formatLLMMessage({
56
+ icon: MessageIcons.INFO,
57
+ issueName: 'Use fs.promises',
58
+ description: 'Use fs.promises API',
59
+ severity: 'LOW',
60
+ fix: 'await fs.promises.readFile() instead of sync operations',
61
+ documentationLink: 'https://nodejs.org/api/fs.html#promises-api',
62
+ }),
63
+ addProperLocking: formatLLMMessage({
64
+ icon: MessageIcons.INFO,
65
+ issueName: 'Add File Locking',
66
+ description: 'Add proper locking mechanism',
67
+ severity: 'LOW',
68
+ fix: 'Use proper-lockfile or similar for concurrent access',
69
+ documentationLink: 'https://github.com/moxystudio/node-proper-lockfile',
70
+ }),
71
+ },
72
+ schema: [
73
+ {
74
+ type: 'object',
75
+ properties: {
76
+ ignoreInTests: {
77
+ type: 'boolean',
78
+ default: true,
79
+ },
80
+ fsMethods: {
81
+ type: 'array',
82
+ items: { type: 'string' },
83
+ default: ['fs.existsSync', 'fs.statSync', 'fs.accessSync'],
84
+ },
85
+ },
86
+ additionalProperties: false,
87
+ },
88
+ ],
89
+ },
90
+ defaultOptions: [
91
+ {
92
+ ignoreInTests: true,
93
+ fsMethods: ['fs.existsSync', 'fs.statSync', 'fs.accessSync'],
94
+ },
95
+ ],
96
+ create(context: TSESLint.RuleContext<MessageIds, RuleOptions>, [options = {}]) {
97
+ const {
98
+ ignoreInTests = true
99
+ }: Options = options || {};
100
+
101
+ const filename = context.getFilename();
102
+ const isTestFile = ignoreInTests && /\.(test|spec)\.(ts|tsx|js|jsx)$/.test(filename);
103
+
104
+ if (isTestFile) {
105
+ return {};
106
+ }
107
+
108
+ const sourceCode = context.sourceCode || context.sourceCode;
109
+
110
+ /**
111
+ * Check for TOCTOU patterns
112
+ */
113
+ function checkCallExpression(node: TSESTree.CallExpression) {
114
+ // 1. Identify the file operation (Use)
115
+ let useMethodName = '';
116
+ if (node.callee.type === 'MemberExpression' && node.callee.property.type === 'Identifier') {
117
+ const objectName = node.callee.object.type === 'Identifier' ? node.callee.object.name : '';
118
+ if (objectName === 'fs' || objectName === 'fsPromises') {
119
+ useMethodName = node.callee.property.name;
120
+ }
121
+ } else if (node.callee.type === 'Identifier') {
122
+ useMethodName = node.callee.name;
123
+ }
124
+
125
+ const riskyUseMethods = ['readFileSync', 'writeFileSync', 'readFile', 'writeFile', 'openSync', 'open', 'unlinkSync', 'unlink'];
126
+ if (!riskyUseMethods.includes(useMethodName)) {
127
+ return;
128
+ }
129
+
130
+ const useArg = node.arguments[0];
131
+ if (!useArg) return;
132
+
133
+ // 2. Walk up to find the condition (Check)
134
+ let current: TSESTree.Node | undefined = node.parent;
135
+ while (current) {
136
+ if (current.type === 'IfStatement') {
137
+ // Extract the condition node
138
+ let condition = current.test;
139
+
140
+ // Handle negated condition: if (!exists(path)) { create(path) } -> also TOCTOU but different logic?
141
+ // Actually TOCTOU is usually Check(exists) -> Use(read).
142
+ // If (!exists) -> create is Check -> Use.
143
+ // But strict TOCTOU is checking state then acting.
144
+
145
+ // If checking for negation
146
+ if (condition.type === 'UnaryExpression' && condition.operator === '!') {
147
+ condition = condition.argument;
148
+ }
149
+
150
+ if (condition.type === 'CallExpression') {
151
+ // Check if it's a file check method
152
+ let checkMethodName = '';
153
+ if (condition.callee.type === 'MemberExpression' && condition.callee.property.type === 'Identifier') {
154
+ checkMethodName = condition.callee.property.name;
155
+ } else if (condition.callee.type === 'Identifier') {
156
+ checkMethodName = condition.callee.name;
157
+ }
158
+
159
+ const checkMethods = ['existsSync', 'statSync', 'accessSync', 'exists', 'stat', 'access'];
160
+ if (checkMethods.includes(checkMethodName)) {
161
+
162
+ // Compare arguments
163
+ const checkArg = condition.arguments[0];
164
+ if (checkArg) {
165
+ // Method 1: Identifier match (same variable)
166
+ if (checkArg.type === 'Identifier' && useArg.type === 'Identifier' && checkArg.name === useArg.name) {
167
+ reportToctou(node);
168
+ return;
169
+ }
170
+
171
+ // Method 2: Text match (fallback)
172
+ const checkArgText = sourceCode.getText(checkArg).replace(/\s/g, '');
173
+ const useArgText = sourceCode.getText(useArg).replace(/\s/g, '');
174
+ if (checkArgText === useArgText) {
175
+ reportToctou(node);
176
+ return;
177
+ }
178
+ }
179
+ }
180
+
181
+ // Handle stats.isFile() / stats.isDirectory() pattern
182
+ if (condition.callee.type === 'MemberExpression' &&
183
+ condition.callee.property.type === 'Identifier' &&
184
+ ['isFile', 'isDirectory'].includes(condition.callee.property.name) &&
185
+ condition.callee.object.type === 'Identifier') {
186
+
187
+ const statsVarName = condition.callee.object.name;
188
+ let currentScope = sourceCode.getScope(condition);
189
+ let variable = null;
190
+
191
+ while (currentScope) {
192
+ variable = currentScope.variables.find(v => v.name === statsVarName);
193
+ if (variable) break;
194
+ currentScope = currentScope.upper;
195
+ }
196
+
197
+ if (variable && variable.defs.length > 0) {
198
+ const def = variable.defs[0];
199
+ if (def.type === 'Variable' && def.node.init && def.node.init.type === 'CallExpression') {
200
+ const init = def.node.init;
201
+ if (init.callee.type === 'MemberExpression' &&
202
+ init.callee.property.type === 'Identifier' &&
203
+ ['statSync', 'lstatSync', 'stat', 'lstat'].includes(init.callee.property.name)) {
204
+
205
+ const statArg = init.arguments[0];
206
+ if (statArg) {
207
+ const checkArgText = sourceCode.getText(statArg).replace(/\s/g, '');
208
+ const useArgText = sourceCode.getText(useArg).replace(/\s/g, '');
209
+ if (checkArgText === useArgText) {
210
+ reportToctou(node);
211
+ return;
212
+ }
213
+ }
214
+ }
215
+ }
216
+ }
217
+ }
218
+ }
219
+ }
220
+ current = current.parent as TSESTree.Node;
221
+ }
222
+ }
223
+
224
+ function reportToctou(node: TSESTree.Node) {
225
+ context.report({
226
+ node,
227
+ messageId: 'toctouVulnerability',
228
+ suggest: [
229
+ {
230
+ messageId: 'useAtomicOperations',
231
+ fix: () => null,
232
+ },
233
+ {
234
+ messageId: 'useFsPromises',
235
+ fix: () => null,
236
+ },
237
+ {
238
+ messageId: 'addProperLocking',
239
+ fix: () => null,
240
+ },
241
+ ],
242
+ });
243
+ }
244
+
245
+ return {
246
+ CallExpression: checkCallExpression,
247
+ };
248
+ },
249
+ });
250
+
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Tests for no-toctou-vulnerability rule
3
+ * Security: CWE-367 (Time-of-Check Time-of-Use)
4
+ */
5
+ import { RuleTester } from '@typescript-eslint/rule-tester';
6
+ import { describe, it, afterAll } from 'vitest';
7
+ import parser from '@typescript-eslint/parser';
8
+ import { noToctouVulnerability } from './index';
9
+
10
+ // Configure RuleTester for Vitest
11
+ RuleTester.afterAll = afterAll;
12
+ RuleTester.it = it;
13
+ RuleTester.itOnly = it.only;
14
+ RuleTester.describe = describe;
15
+
16
+ const ruleTester = new RuleTester({
17
+ languageOptions: {
18
+ parser,
19
+ ecmaVersion: 2022,
20
+ sourceType: 'module',
21
+ },
22
+ });
23
+
24
+ describe('no-toctou-vulnerability', () => {
25
+ describe('Valid Code', () => {
26
+ ruleTester.run('valid - safe file operations', noToctouVulnerability, {
27
+ valid: [
28
+ 'const data = fs.readFileSync("file.txt");',
29
+ 'fs.writeFileSync("output.txt", buffer);',
30
+ 'const stats = fs.statSync("file.txt");',
31
+ ],
32
+ invalid: [],
33
+ });
34
+ });
35
+
36
+ describe('Invalid Code - TOCTOU Vulnerabilities', () => {
37
+ ruleTester.run('invalid - check-then-use patterns', noToctouVulnerability, {
38
+ valid: [],
39
+ invalid: [
40
+ {
41
+ code: `
42
+ if (fs.existsSync("file.txt")) {
43
+ const data = fs.readFileSync("file.txt");
44
+ }
45
+ `,
46
+ errors: [{ messageId: 'toctouVulnerability' }],
47
+ },
48
+ {
49
+ code: `
50
+ const stats = fs.statSync("file.txt");
51
+ if (stats.isFile()) {
52
+ fs.unlinkSync("file.txt");
53
+ }
54
+ `,
55
+ errors: [{ messageId: 'toctouVulnerability' }],
56
+ },
57
+ ],
58
+ });
59
+ });
60
+ });