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
@@ -0,0 +1,399 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.noMissingCorsCheck = void 0;
4
+ const eslint_devkit_1 = require("@interlace/eslint-devkit");
5
+ const eslint_devkit_2 = require("@interlace/eslint-devkit");
6
+ /**
7
+ * Check if a string matches any ignore pattern
8
+ */
9
+ function matchesIgnorePattern(text, ignorePatterns) {
10
+ return ignorePatterns.some(pattern => {
11
+ try {
12
+ const regex = new RegExp(pattern, 'i');
13
+ return regex.test(text);
14
+ }
15
+ catch {
16
+ return false;
17
+ }
18
+ });
19
+ }
20
+ exports.noMissingCorsCheck = (0, eslint_devkit_2.createRule)({
21
+ name: 'no-missing-cors-check',
22
+ meta: {
23
+ type: 'problem',
24
+ deprecated: true,
25
+ replacedBy: ['@see eslint-plugin-express-security/no-permissive-cors'],
26
+ docs: {
27
+ description: 'Detects missing CORS validation (wildcard CORS, missing origin check)',
28
+ },
29
+ hasSuggestions: true,
30
+ messages: {
31
+ missingCorsCheck: (0, eslint_devkit_1.formatLLMMessage)({
32
+ icon: eslint_devkit_1.MessageIcons.SECURITY,
33
+ issueName: 'Missing CORS Validation',
34
+ cwe: 'CWE-346',
35
+ description: 'Missing CORS validation detected: {{issue}}',
36
+ severity: 'HIGH',
37
+ fix: '{{safeAlternative}}',
38
+ documentationLink: 'https://cwe.mitre.org/data/definitions/346.html',
39
+ }),
40
+ useOriginValidation: (0, eslint_devkit_1.formatLLMMessage)({
41
+ icon: eslint_devkit_1.MessageIcons.INFO,
42
+ issueName: 'Validate Origin',
43
+ description: 'Validate CORS origin',
44
+ severity: 'LOW',
45
+ fix: 'cors({ origin: (origin, cb) => allowedOrigins.includes(origin) ? cb(null, true) : cb(new Error()) })',
46
+ documentationLink: 'https://github.com/expressjs/cors#configuration-options',
47
+ }),
48
+ useCorsMiddleware: (0, eslint_devkit_1.formatLLMMessage)({
49
+ icon: eslint_devkit_1.MessageIcons.INFO,
50
+ issueName: 'Use CORS Middleware',
51
+ description: 'Use CORS middleware with origin validation',
52
+ severity: 'LOW',
53
+ fix: 'app.use(cors({ origin: allowedOrigins }))',
54
+ documentationLink: 'https://github.com/expressjs/cors',
55
+ }),
56
+ },
57
+ schema: [
58
+ {
59
+ type: 'object',
60
+ properties: {
61
+ allowInTests: {
62
+ type: 'boolean',
63
+ default: false,
64
+ description: 'Allow missing CORS checks in test files',
65
+ },
66
+ trustedLibraries: {
67
+ type: 'array',
68
+ items: { type: 'string' },
69
+ default: [],
70
+ description: 'Custom CORS libraries to trust (wildcard origins in these libraries will not be reported)',
71
+ },
72
+ ignorePatterns: {
73
+ type: 'array',
74
+ items: { type: 'string' },
75
+ default: [],
76
+ description: 'Additional safe patterns to ignore',
77
+ },
78
+ },
79
+ additionalProperties: false,
80
+ },
81
+ ],
82
+ },
83
+ defaultOptions: [
84
+ {
85
+ allowInTests: false,
86
+ trustedLibraries: [], // Empty by default - users can add custom CORS libraries they trust
87
+ ignorePatterns: [],
88
+ },
89
+ ],
90
+ create(context, [options = {}]) {
91
+ const { allowInTests = false, trustedLibraries: corsTrustedLibraries = [], ignorePatterns = [], } = options;
92
+ const trustedLibraries = corsTrustedLibraries;
93
+ const filename = context.getFilename();
94
+ const isTestFile = allowInTests && /\.(test|spec)\.(ts|tsx|js|jsx)$/.test(filename);
95
+ const sourceCode = context.sourceCode || context.sourceCode;
96
+ function checkLiteral(node) {
97
+ if (isTestFile) {
98
+ return;
99
+ }
100
+ // Check for wildcard CORS origin
101
+ if (node.value === '*' && typeof node.value === 'string') {
102
+ const text = sourceCode.getText(node);
103
+ // Check if it matches any ignore pattern
104
+ if (matchesIgnorePattern(text, ignorePatterns)) {
105
+ return;
106
+ }
107
+ // Check if it's in contexts handled by other checkers
108
+ // 1. setHeader/header calls - checkMemberExpression handles these
109
+ // 2. app.use(cors({ origin: "*" })) - checkCallExpression handles these with suggestions
110
+ let shouldSkip = false;
111
+ let current = node;
112
+ while (current && current.parent) {
113
+ current = current.parent;
114
+ if (current.type === 'CallExpression') {
115
+ const callText = sourceCode.getText(current);
116
+ // Check if it's a setHeader/header call with Access-Control-Allow-Origin
117
+ // Skip these - checkMemberExpression handles them
118
+ if (/\b(setHeader|header)\s*\(/i.test(callText) && /\bAccess-Control-Allow-Origin\b/i.test(callText)) {
119
+ shouldSkip = true;
120
+ break;
121
+ }
122
+ // Check if it's app.use(cors({ origin: "*" })) - checkCallExpression handles these with suggestions
123
+ if (/\buse\s*\(/i.test(callText) && /\bcors\s*\(/i.test(callText)) {
124
+ // Check if the literal is in an object property named "origin"
125
+ if (node.parent && node.parent.type === 'Property') {
126
+ const prop = node.parent;
127
+ if (prop.key.type === 'Identifier' && prop.key.name === 'origin') {
128
+ shouldSkip = true;
129
+ break;
130
+ }
131
+ }
132
+ }
133
+ }
134
+ }
135
+ // Skip if it's in a context handled by another checker
136
+ if (shouldSkip) {
137
+ return;
138
+ }
139
+ // Check if it's in a CORS-related context
140
+ // Only report if it's actually in a CORS configuration (app.use(cors(...)), etc.)
141
+ // Not just any object with origin: "*"
142
+ let isActualCorsContext = false;
143
+ // Check if it's in app.use(cors(...)) or similar
144
+ current = node;
145
+ while (current && current.parent) {
146
+ current = current.parent;
147
+ if (current.type === 'CallExpression') {
148
+ const callText = sourceCode.getText(current);
149
+ // Check if it's a CORS middleware call
150
+ if (/\b(use|cors)\s*\(/i.test(callText) && /\bcors\s*\(/i.test(callText)) {
151
+ isActualCorsContext = true;
152
+ break;
153
+ }
154
+ }
155
+ }
156
+ // Also check if it's in an object property with name "origin" or "allowedOrigins"
157
+ // but only if it's in a CORS-related call expression
158
+ if (node.parent && node.parent.type === 'Property') {
159
+ const prop = node.parent;
160
+ if (prop.key.type === 'Identifier') {
161
+ const keyName = prop.key.name.toLowerCase();
162
+ if (keyName === 'origin' || keyName === 'allowedorigins') {
163
+ // Check if this property is in a CORS call context
164
+ let inCorsCall = false;
165
+ let checkNode = prop;
166
+ while (checkNode && checkNode.parent) {
167
+ checkNode = checkNode.parent;
168
+ if (checkNode.type === 'CallExpression') {
169
+ const callText = sourceCode.getText(checkNode);
170
+ if (/\bcors\s*\(/i.test(callText) ||
171
+ (/\buse\s*\(/i.test(callText) && /\bcors/i.test(callText))) {
172
+ inCorsCall = true;
173
+ break;
174
+ }
175
+ }
176
+ }
177
+ if (inCorsCall) {
178
+ // Always report wildcard CORS origin - it's never safe
179
+ context.report({
180
+ node,
181
+ messageId: 'missingCorsCheck',
182
+ data: {
183
+ issue: 'Wildcard CORS origin (*) allows all origins',
184
+ safeAlternative: 'Use origin validation: app.use(cors({ origin: (origin, callback) => { if (allowedOrigins.includes(origin)) callback(null, true); else callback(new Error("Not allowed")); } } }));',
185
+ },
186
+ suggest: [
187
+ {
188
+ messageId: 'useOriginValidation',
189
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
190
+ fix: (_fixer) => null,
191
+ },
192
+ ],
193
+ });
194
+ return;
195
+ }
196
+ }
197
+ }
198
+ }
199
+ // Only report if it's in an actual CORS context
200
+ if (isActualCorsContext) {
201
+ // Always report wildcard CORS origin - it's never safe
202
+ context.report({
203
+ node,
204
+ messageId: 'missingCorsCheck',
205
+ data: {
206
+ issue: 'Wildcard CORS origin (*) allows all origins',
207
+ safeAlternative: 'Use origin validation: app.use(cors({ origin: (origin, callback) => { if (allowedOrigins.includes(origin)) callback(null, true); else callback(new Error("Not allowed")); } } }));',
208
+ },
209
+ suggest: [
210
+ {
211
+ messageId: 'useOriginValidation',
212
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
213
+ fix: (_fixer) => null,
214
+ },
215
+ ],
216
+ });
217
+ }
218
+ }
219
+ }
220
+ function checkCallExpression(node) {
221
+ if (isTestFile) {
222
+ return;
223
+ }
224
+ // Check for app.use(cors({ origin: "*" })) or similar
225
+ if (node.callee.type === 'MemberExpression') {
226
+ const property = node.callee.property;
227
+ if (property.type === 'Identifier' && property.name === 'use') {
228
+ // Check if CORS is being used
229
+ const text = sourceCode.getText(node);
230
+ // Check if it matches any ignore pattern
231
+ if (matchesIgnorePattern(text, ignorePatterns)) {
232
+ return;
233
+ }
234
+ // Check if it's a CORS middleware call
235
+ // Check for cors() or trusted library calls
236
+ const firstArg = node.arguments.length > 0 ? node.arguments[0] : null;
237
+ let isCorsCall = /\bcors\s*\(/i.test(text);
238
+ if (!isCorsCall && firstArg && firstArg.type === 'CallExpression' && firstArg.callee.type === 'Identifier') {
239
+ const callee = firstArg.callee;
240
+ const calleeName = callee.name.toLowerCase();
241
+ // Check if it's the standard 'cors' library or a trusted library
242
+ isCorsCall = calleeName === 'cors' || trustedLibraries.some(lib => {
243
+ return calleeName.includes(lib.toLowerCase());
244
+ });
245
+ }
246
+ // Check if it's a trusted library - skip if explicitly trusted
247
+ let isTrustedLibrary = false;
248
+ if (firstArg && firstArg.type === 'CallExpression' && firstArg.callee.type === 'Identifier') {
249
+ const calleeName = firstArg.callee.name.toLowerCase();
250
+ isTrustedLibrary = trustedLibraries.some(lib => calleeName.includes(lib.toLowerCase()));
251
+ }
252
+ if (isTrustedLibrary) {
253
+ return; // Trusted library, skip
254
+ }
255
+ // Check if it's a CORS call
256
+ if (/\bcors\s*\(/i.test(text) || isCorsCall) {
257
+ // Check arguments for wildcard origin
258
+ // For app.use(cors({ origin: "*" })), we need to check the arguments to cors(), not app.use()
259
+ const corsCallArg = firstArg && firstArg.type === 'CallExpression' ? firstArg : null;
260
+ const argsToCheck = corsCallArg ? corsCallArg.arguments : node.arguments;
261
+ for (const arg of argsToCheck) {
262
+ if (arg.type === 'ObjectExpression') {
263
+ // Check for origin property with wildcard value
264
+ for (const prop of arg.properties) {
265
+ if (prop.type === 'Property' &&
266
+ prop.key.type === 'Identifier' &&
267
+ prop.key.name === 'origin' &&
268
+ prop.value.type === 'Literal' &&
269
+ prop.value.value === '*') {
270
+ context.report({
271
+ node: prop.value,
272
+ messageId: 'missingCorsCheck',
273
+ data: {
274
+ issue: 'Wildcard CORS origin (*) allows all origins',
275
+ safeAlternative: 'Use origin validation: app.use(cors({ origin: (origin, callback) => { if (allowedOrigins.includes(origin)) callback(null, true); else callback(new Error("Not allowed")); } } }));',
276
+ },
277
+ suggest: [
278
+ {
279
+ messageId: 'useOriginValidation',
280
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
281
+ fix: (_fixer) => null,
282
+ },
283
+ ],
284
+ });
285
+ }
286
+ }
287
+ }
288
+ else if (arg.type === 'Identifier') {
289
+ // Check if this identifier was assigned an object literal with origin: "*"
290
+ // For cases like: const config = { origin: "*" }; app.use(cors(config));
291
+ const varName = arg.name;
292
+ // Traverse the AST to find the variable declaration
293
+ let current = node;
294
+ while (current) {
295
+ if (current.type === 'Program' || current.type === 'FunctionDeclaration' || current.type === 'FunctionExpression' || current.type === 'ArrowFunctionExpression') {
296
+ // Search for variable declarations in this scope
297
+ const scopeBody = current.type === 'Program' ? current.body :
298
+ (current.type === 'FunctionDeclaration' || current.type === 'FunctionExpression' || current.type === 'ArrowFunctionExpression') ?
299
+ (current.body.type === 'BlockStatement' ? current.body.body : []) : [];
300
+ for (const stmt of scopeBody) {
301
+ if (stmt.type === 'VariableDeclaration') {
302
+ for (const declarator of stmt.declarations) {
303
+ if (declarator.id.type === 'Identifier' && declarator.id.name === varName && declarator.init) {
304
+ // Check if init is an object literal with origin: "*"
305
+ if (declarator.init.type === 'ObjectExpression') {
306
+ for (const prop of declarator.init.properties) {
307
+ if (prop.type === 'Property' &&
308
+ prop.key.type === 'Identifier' &&
309
+ prop.key.name === 'origin' &&
310
+ prop.value.type === 'Literal' &&
311
+ prop.value.value === '*') {
312
+ context.report({
313
+ node: arg,
314
+ messageId: 'missingCorsCheck',
315
+ data: {
316
+ issue: 'Wildcard CORS origin (*) allows all origins',
317
+ safeAlternative: 'Use origin validation: app.use(cors({ origin: (origin, callback) => { if (allowedOrigins.includes(origin)) callback(null, true); else callback(new Error("Not allowed")); } } }));',
318
+ },
319
+ suggest: [
320
+ {
321
+ messageId: 'useOriginValidation',
322
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
323
+ fix: (_fixer) => null,
324
+ },
325
+ ],
326
+ });
327
+ return; // Found and reported, exit
328
+ }
329
+ }
330
+ }
331
+ }
332
+ }
333
+ }
334
+ }
335
+ break; // Only check the immediate scope
336
+ }
337
+ if (current.parent) {
338
+ current = current.parent;
339
+ }
340
+ else {
341
+ break;
342
+ }
343
+ }
344
+ }
345
+ }
346
+ }
347
+ }
348
+ }
349
+ }
350
+ function checkMemberExpression(node) {
351
+ if (isTestFile) {
352
+ return;
353
+ }
354
+ // Check for Access-Control-Allow-Origin header without validation
355
+ if (node.property.type === 'Identifier') {
356
+ const propertyName = node.property.name;
357
+ if (propertyName === 'setHeader' || propertyName === 'header') {
358
+ // Check if it matches any ignore pattern
359
+ const text = sourceCode.getText(node);
360
+ if (matchesIgnorePattern(text, ignorePatterns)) {
361
+ return;
362
+ }
363
+ // Check if it's setting CORS headers
364
+ // Need to check the full call expression, not just the member expression
365
+ const parent = node.parent;
366
+ if (parent && parent.type === 'CallExpression') {
367
+ const callText = sourceCode.getText(parent);
368
+ if (/\bAccess-Control-Allow-Origin\b/i.test(callText)) {
369
+ // Check if the value is a wildcard
370
+ const args = parent.arguments;
371
+ if (args.length >= 2 && args[1].type === 'Literal' && args[1].value === '*') {
372
+ context.report({
373
+ node: args[1],
374
+ messageId: 'missingCorsCheck',
375
+ data: {
376
+ issue: 'Wildcard CORS header allows all origins',
377
+ safeAlternative: 'Validate origin before setting header: res.setHeader("Access-Control-Allow-Origin", allowedOrigins.includes(origin) ? origin : "null");',
378
+ },
379
+ suggest: [
380
+ {
381
+ messageId: 'useOriginValidation',
382
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
383
+ fix: (_fixer) => null,
384
+ },
385
+ ],
386
+ });
387
+ }
388
+ }
389
+ }
390
+ }
391
+ }
392
+ }
393
+ return {
394
+ Literal: checkLiteral,
395
+ CallExpression: checkCallExpression,
396
+ MemberExpression: checkMemberExpression,
397
+ };
398
+ },
399
+ });
@@ -0,0 +1,11 @@
1
+ export interface Options {
2
+ /** Allow missing CSRF protection in test files. Default: false */
3
+ allowInTests?: boolean;
4
+ /** CSRF middleware patterns to recognize. Default: ['csrf', 'csurf', 'csrfProtection', 'verifyCsrfToken'] */
5
+ csrfMiddlewarePatterns?: string[];
6
+ /** HTTP methods that require CSRF protection. Default: ['post', 'put', 'delete', 'patch'] */
7
+ protectedMethods?: string[];
8
+ /** Additional safe patterns to ignore. Default: [] */
9
+ ignorePatterns?: string[];
10
+ }
11
+ export declare const noMissingCsrfProtection: ESLintUtils.RuleModule<MessageIds, Options, unknown, ESLintUtils.RuleListener>;
@@ -0,0 +1,180 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.noMissingCsrfProtection = void 0;
4
+ const eslint_devkit_1 = require("@interlace/eslint-devkit");
5
+ const eslint_devkit_2 = require("@interlace/eslint-devkit");
6
+ /**
7
+ * Default CSRF middleware patterns
8
+ */
9
+ const DEFAULT_CSRF_MIDDLEWARE_PATTERNS = [
10
+ 'csrf',
11
+ 'csurf',
12
+ 'csrfProtection',
13
+ 'verifyCsrfToken',
14
+ 'csrfToken',
15
+ 'validateCsrf',
16
+ 'checkCsrf',
17
+ 'csrfMiddleware',
18
+ ];
19
+ /**
20
+ * Default HTTP methods that require CSRF protection
21
+ */
22
+ const DEFAULT_PROTECTED_METHODS = ['post', 'put', 'delete', 'patch'];
23
+ /**
24
+ * Check if a string matches any ignore pattern
25
+ */
26
+ function matchesIgnorePattern(text, patterns) {
27
+ return patterns.some(pattern => {
28
+ try {
29
+ const regex = new RegExp(pattern, 'i');
30
+ return regex.test(text);
31
+ }
32
+ catch {
33
+ return text.toLowerCase().includes(pattern.toLowerCase());
34
+ }
35
+ });
36
+ }
37
+ exports.noMissingCsrfProtection = (0, eslint_devkit_2.createRule)({
38
+ name: 'no-missing-csrf-protection',
39
+ meta: {
40
+ type: 'problem',
41
+ deprecated: true,
42
+ replacedBy: ['@see eslint-plugin-express-security/require-csrf-protection'],
43
+ docs: {
44
+ description: 'Detects missing CSRF token validation in POST/PUT/DELETE requests',
45
+ },
46
+ hasSuggestions: true,
47
+ messages: {
48
+ missingCsrfProtection: (0, eslint_devkit_1.formatLLMMessage)({
49
+ icon: eslint_devkit_1.MessageIcons.SECURITY,
50
+ issueName: 'Missing CSRF Protection',
51
+ cwe: 'CWE-352',
52
+ description: 'Missing CSRF protection detected: {{issue}}',
53
+ severity: 'HIGH',
54
+ fix: '{{safeAlternative}}',
55
+ documentationLink: 'https://cwe.mitre.org/data/definitions/352.html',
56
+ }),
57
+ addCsrfValidation: (0, eslint_devkit_1.formatLLMMessage)({
58
+ icon: eslint_devkit_1.MessageIcons.INFO,
59
+ issueName: 'Add CSRF Validation',
60
+ description: 'Add CSRF middleware',
61
+ severity: 'LOW',
62
+ fix: 'app.use(csrf({ cookie: true }))',
63
+ documentationLink: 'https://github.com/expressjs/csurf',
64
+ }),
65
+ },
66
+ schema: [
67
+ {
68
+ type: 'object',
69
+ properties: {
70
+ allowInTests: {
71
+ type: 'boolean',
72
+ default: false,
73
+ description: 'Allow missing CSRF protection in test files',
74
+ },
75
+ csrfMiddlewarePatterns: {
76
+ type: 'array',
77
+ items: { type: 'string' },
78
+ default: [],
79
+ description: 'CSRF middleware patterns to recognize',
80
+ },
81
+ protectedMethods: {
82
+ type: 'array',
83
+ items: { type: 'string' },
84
+ default: [],
85
+ description: 'HTTP methods that require CSRF protection',
86
+ },
87
+ ignorePatterns: {
88
+ type: 'array',
89
+ items: { type: 'string' },
90
+ default: [],
91
+ description: 'Additional safe patterns to ignore',
92
+ },
93
+ },
94
+ additionalProperties: false,
95
+ },
96
+ ],
97
+ },
98
+ defaultOptions: [
99
+ {
100
+ allowInTests: false,
101
+ csrfMiddlewarePatterns: [],
102
+ protectedMethods: [],
103
+ ignorePatterns: [],
104
+ },
105
+ ],
106
+ create(context, [options = {}]) {
107
+ const { allowInTests = false, csrfMiddlewarePatterns, protectedMethods: customProtectedMethods, ignorePatterns = [], } = options;
108
+ const csrfPatterns = csrfMiddlewarePatterns && csrfMiddlewarePatterns.length > 0
109
+ ? csrfMiddlewarePatterns
110
+ : DEFAULT_CSRF_MIDDLEWARE_PATTERNS;
111
+ const protectedMethods = customProtectedMethods && customProtectedMethods.length > 0
112
+ ? customProtectedMethods
113
+ : DEFAULT_PROTECTED_METHODS;
114
+ // Pre-compute Set for O(1) lookups (performance optimization)
115
+ const protectedMethodsSet = new Set(protectedMethods.map(m => m.toLowerCase()));
116
+ const filename = context.filename;
117
+ const isTestFile = allowInTests && /\.(test|spec)\.(ts|tsx|js|jsx)$/.test(filename);
118
+ const sourceCode = context.sourceCode;
119
+ function checkCallExpression(node) {
120
+ if (isTestFile) {
121
+ return;
122
+ }
123
+ const callee = node.callee;
124
+ const callText = sourceCode.getText(node);
125
+ // Check if it matches any ignore pattern
126
+ if (matchesIgnorePattern(callText, ignorePatterns)) {
127
+ return;
128
+ }
129
+ // Check for route handler methods (app.post, router.put, etc.)
130
+ if (callee.type === eslint_devkit_1.AST_NODE_TYPES.MemberExpression && callee.property.type === eslint_devkit_1.AST_NODE_TYPES.Identifier) {
131
+ const methodName = callee.property.name;
132
+ // Only check if it's a route handler that requires CSRF (O(1) Set lookup)
133
+ if (protectedMethodsSet.has(methodName.toLowerCase())) {
134
+ // Must have at least 2 arguments (path and handler)
135
+ if (node.arguments.length < 2) {
136
+ return;
137
+ }
138
+ // Check if CSRF middleware is in the route chain arguments
139
+ let hasCsrfInChain = false;
140
+ // Check if any argument (after the first path argument) is a CSRF middleware
141
+ // Skip the first argument (path) and check the rest
142
+ for (let i = 1; i < node.arguments.length; i++) {
143
+ const arg = node.arguments[i];
144
+ const argText = sourceCode.getText(arg);
145
+ if (csrfPatterns.some(pattern => argText.toLowerCase().includes(pattern.toLowerCase()))) {
146
+ hasCsrfInChain = true;
147
+ break;
148
+ }
149
+ }
150
+ if (!hasCsrfInChain) {
151
+ context.report({
152
+ node,
153
+ messageId: 'missingCsrfProtection',
154
+ data: {
155
+ issue: `${methodName.toUpperCase()} route handler missing CSRF protection`,
156
+ safeAlternative: `Add CSRF middleware: app.${methodName}("/path", csrf(), handler) or use app.use(csrf()) globally`,
157
+ },
158
+ suggest: [
159
+ {
160
+ messageId: 'addCsrfValidation',
161
+ fix(fixer) {
162
+ // Add CSRF middleware after the first argument (path)
163
+ const firstArg = node.arguments[0];
164
+ if (firstArg) {
165
+ return fixer.insertTextAfter(firstArg, ', csrf()');
166
+ }
167
+ return null;
168
+ },
169
+ },
170
+ ],
171
+ });
172
+ }
173
+ }
174
+ }
175
+ }
176
+ return {
177
+ CallExpression: checkCallExpression,
178
+ };
179
+ },
180
+ });
@@ -0,0 +1,7 @@
1
+ export interface Options {
2
+ /** Required security headers. Default: ['Content-Security-Policy', 'X-Frame-Options', 'X-Content-Type-Options'] */
3
+ requiredHeaders?: string[];
4
+ /** Ignore in test files. Default: true */
5
+ ignoreInTests?: boolean;
6
+ }
7
+ export declare const noMissingSecurityHeaders: ESLintUtils.RuleModule<MessageIds, Options, unknown, ESLintUtils.RuleListener>;