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,560 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.detectObjectInjection = void 0;
4
+ /**
5
+ * ESLint Rule: detect-object-injection
6
+ * Detects variable[key] as a left- or right-hand assignment operand (prototype pollution)
7
+ * LLM-optimized with comprehensive object injection prevention guidance
8
+ *
9
+ * Type-Aware Enhancement:
10
+ * This rule uses TypeScript type information when available to reduce false positives.
11
+ * If a property key is constrained to a union of string literals (e.g., 'name' | 'email'),
12
+ * the access is considered safe because the values are statically known at compile time.
13
+ *
14
+ * @see https://portswigger.net/web-security/prototype-pollution
15
+ * @see https://cwe.mitre.org/data/definitions/915.html
16
+ */
17
+ const eslint_devkit_1 = require("@interlace/eslint-devkit");
18
+ const eslint_devkit_2 = require("@interlace/eslint-devkit");
19
+ const eslint_devkit_3 = require("@interlace/eslint-devkit");
20
+ const OBJECT_INJECTION_PATTERNS = [
21
+ {
22
+ pattern: '__proto__',
23
+ dangerous: true,
24
+ vulnerability: 'prototype-pollution',
25
+ safeAlternative: 'Object.create(null) or Map',
26
+ example: {
27
+ bad: 'obj[userInput] = value; // if userInput is "__proto__"',
28
+ good: 'const map = new Map(); map.set(userInput, value);'
29
+ },
30
+ effort: '15-20 minutes',
31
+ riskLevel: 'critical'
32
+ },
33
+ {
34
+ pattern: 'prototype',
35
+ dangerous: true,
36
+ vulnerability: 'prototype-pollution',
37
+ safeAlternative: 'Avoid prototype manipulation',
38
+ example: {
39
+ bad: 'obj[userInput] = value; // if userInput is "prototype"',
40
+ good: 'if (!obj.hasOwnProperty(userInput)) obj[userInput] = value;'
41
+ },
42
+ effort: '10-15 minutes',
43
+ riskLevel: 'high'
44
+ },
45
+ {
46
+ pattern: 'constructor',
47
+ dangerous: true,
48
+ vulnerability: 'method-injection',
49
+ safeAlternative: 'Validate property names against whitelist',
50
+ example: {
51
+ bad: 'obj[userInput] = value; // if userInput is "constructor"',
52
+ good: 'const ALLOWED_KEYS = [\'name\', \'age\', \'email\']; if (ALLOWED_KEYS.includes(userInput)) obj[userInput] = value;'
53
+ },
54
+ effort: '10-15 minutes',
55
+ riskLevel: 'medium'
56
+ }
57
+ ];
58
+ exports.detectObjectInjection = (0, eslint_devkit_3.createRule)({
59
+ name: 'detect-object-injection',
60
+ meta: {
61
+ type: 'problem',
62
+ docs: {
63
+ description: 'Detects variable[key] as a left- or right-hand assignment operand',
64
+ },
65
+ messages: {
66
+ // 🎯 Token optimization: 37% reduction (54→34 tokens) - removes verbose current/fix/doc labels
67
+ objectInjection: (0, eslint_devkit_2.formatLLMMessage)({
68
+ icon: eslint_devkit_2.MessageIcons.WARNING,
69
+ issueName: 'Object injection',
70
+ cwe: 'CWE-915',
71
+ description: 'Object injection/Prototype pollution (incl. model/tool outputs)',
72
+ severity: '{{riskLevel}}',
73
+ fix: '{{safeAlternative}}',
74
+ documentationLink: 'https://portswigger.net/web-security/prototype-pollution',
75
+ }),
76
+ useMapInstead: (0, eslint_devkit_2.formatLLMMessage)({
77
+ icon: eslint_devkit_2.MessageIcons.INFO,
78
+ issueName: 'Use Map',
79
+ description: 'Use Map instead of plain objects',
80
+ severity: 'LOW',
81
+ fix: 'const map = new Map(); map.set(key, value);',
82
+ documentationLink: 'https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map',
83
+ }),
84
+ useHasOwnProperty: (0, eslint_devkit_2.formatLLMMessage)({
85
+ icon: eslint_devkit_2.MessageIcons.INFO,
86
+ issueName: 'Use hasOwnProperty',
87
+ description: 'Check hasOwnProperty to avoid prototype properties',
88
+ severity: 'LOW',
89
+ fix: 'if (obj.hasOwnProperty(key)) { obj[key] = value; }',
90
+ documentationLink: 'https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwnProperty',
91
+ }),
92
+ whitelistKeys: (0, eslint_devkit_2.formatLLMMessage)({
93
+ icon: eslint_devkit_2.MessageIcons.INFO,
94
+ issueName: 'Whitelist Keys',
95
+ description: 'Whitelist allowed property names',
96
+ severity: 'LOW',
97
+ fix: 'const ALLOWED = ["name", "email"]; if (ALLOWED.includes(key)) obj[key] = value; // reject model/tool-supplied unknown keys',
98
+ documentationLink: 'https://portswigger.net/web-security/prototype-pollution',
99
+ }),
100
+ useObjectCreate: (0, eslint_devkit_2.formatLLMMessage)({
101
+ icon: eslint_devkit_2.MessageIcons.INFO,
102
+ issueName: 'Use Object.create(null)',
103
+ description: 'Create clean objects without prototypes',
104
+ severity: 'LOW',
105
+ fix: 'const obj = Object.create(null);',
106
+ documentationLink: 'https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create',
107
+ }),
108
+ freezePrototypes: (0, eslint_devkit_2.formatLLMMessage)({
109
+ icon: eslint_devkit_2.MessageIcons.INFO,
110
+ issueName: 'Freeze Prototypes',
111
+ description: 'Freeze Object.prototype to prevent pollution',
112
+ severity: 'LOW',
113
+ fix: 'Object.freeze(Object.prototype);',
114
+ documentationLink: 'https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze',
115
+ }),
116
+ strategyValidate: (0, eslint_devkit_2.formatLLMMessage)({
117
+ icon: eslint_devkit_2.MessageIcons.STRATEGY,
118
+ issueName: 'Validate Input',
119
+ description: 'Add input validation before property access',
120
+ severity: 'LOW',
121
+ fix: 'Validate key against allowed values before access',
122
+ documentationLink: 'https://portswigger.net/web-security/prototype-pollution',
123
+ }),
124
+ strategyWhitelist: (0, eslint_devkit_2.formatLLMMessage)({
125
+ icon: eslint_devkit_2.MessageIcons.STRATEGY,
126
+ issueName: 'Whitelist Properties',
127
+ description: 'Whitelist allowed property names only',
128
+ severity: 'LOW',
129
+ fix: 'Define allowed keys and validate against them',
130
+ documentationLink: 'https://portswigger.net/web-security/prototype-pollution',
131
+ }),
132
+ strategyFreeze: (0, eslint_devkit_2.formatLLMMessage)({
133
+ icon: eslint_devkit_2.MessageIcons.STRATEGY,
134
+ issueName: 'Freeze Prototypes',
135
+ description: 'Freeze prototypes to prevent pollution',
136
+ severity: 'LOW',
137
+ fix: 'Object.freeze(Object.prototype) at app startup',
138
+ documentationLink: 'https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze',
139
+ })
140
+ },
141
+ schema: [
142
+ {
143
+ type: 'object',
144
+ properties: {
145
+ allowLiterals: {
146
+ type: 'boolean',
147
+ default: false,
148
+ description: 'Allow bracket notation with literal strings'
149
+ },
150
+ additionalMethods: {
151
+ type: 'array',
152
+ items: { type: 'string' },
153
+ default: [],
154
+ description: 'Additional object methods to check for injection'
155
+ },
156
+ dangerousProperties: {
157
+ type: 'array',
158
+ items: { type: 'string' },
159
+ default: ['__proto__', 'prototype', 'constructor'],
160
+ description: 'Properties to consider dangerous'
161
+ },
162
+ strategy: {
163
+ type: 'string',
164
+ enum: ['validate', 'whitelist', 'freeze', 'auto'],
165
+ default: 'auto',
166
+ description: 'Strategy for fixing object injection (auto = smart detection)'
167
+ }
168
+ },
169
+ additionalProperties: false,
170
+ },
171
+ ],
172
+ },
173
+ defaultOptions: [
174
+ {
175
+ allowLiterals: false,
176
+ additionalMethods: [],
177
+ dangerousProperties: ['__proto__', 'prototype', 'constructor'],
178
+ strategy: 'auto'
179
+ },
180
+ ],
181
+ create(context) {
182
+ const options = context.options[0] || {};
183
+ const { allowLiterals = false, dangerousProperties = ['__proto__', 'prototype', 'constructor'], } = options || {};
184
+ // Track MemberExpressions that are part of AssignmentExpressions to avoid double-reporting
185
+ const handledMemberExpressions = new WeakSet();
186
+ // Check if TypeScript parser services are available for type-aware checking
187
+ const hasTypeInfo = (0, eslint_devkit_2.hasParserServices)(context);
188
+ const parserServices = hasTypeInfo ? (0, eslint_devkit_2.getParserServices)(context) : null;
189
+ /**
190
+ * Check if a node is a literal string (potentially safe)
191
+ */
192
+ const isLiteralString = (node) => {
193
+ return node.type === eslint_devkit_1.AST_NODE_TYPES.Literal && typeof node.value === 'string';
194
+ };
195
+ /**
196
+ * Check if a property is part of a typed union (safe access)
197
+ *
198
+ * Type-Aware Enhancement:
199
+ * When TypeScript parser services are available, we can check if a variable
200
+ * is typed as a union of string literals (e.g., 'name' | 'email').
201
+ * Such accesses are safe because the values are statically constrained.
202
+ *
203
+ * @example
204
+ * // This is now detected as SAFE (no false positive):
205
+ * const key: 'name' | 'email' = getKey();
206
+ * obj[key] = value;
207
+ *
208
+ * // This is still detected as DANGEROUS:
209
+ * const key: string = getUserInput();
210
+ * obj[key] = value;
211
+ */
212
+ const isTypedUnionAccess = (propertyNode) => {
213
+ // Check if property is a literal string (typed access like obj['name'])
214
+ if (isLiteralString(propertyNode)) {
215
+ return true; // Literal strings are safe - they're typed at compile time
216
+ }
217
+ // Type-aware check: If we have TypeScript type information, check if the
218
+ // property key is constrained to a union of safe string literals
219
+ /* c8 ignore start -- TypeScript parser services often unavailable in RuleTester */
220
+ if (parserServices && propertyNode.type === eslint_devkit_1.AST_NODE_TYPES.Identifier) {
221
+ try {
222
+ const type = (0, eslint_devkit_2.getTypeOfNode)(propertyNode, parserServices);
223
+ // Check if the type is a union of safe string literals
224
+ // (excludes '__proto__', 'prototype', 'constructor')
225
+ if ((0, eslint_devkit_2.isUnionOfSafeStringLiterals)(type, dangerousProperties)) {
226
+ return true; // Safe - statically constrained to safe values
227
+ }
228
+ // Also check for single string literal type (e.g., const key: 'name' = ...)
229
+ const literalValues = (0, eslint_devkit_2.getStringLiteralValues)(type);
230
+ if (literalValues && literalValues.length === 1) {
231
+ // Single literal - safe if not dangerous
232
+ if (!dangerousProperties.includes(literalValues[0])) {
233
+ return true;
234
+ }
235
+ }
236
+ }
237
+ catch {
238
+ // If type checking fails, fall back to treating as potentially dangerous
239
+ // This can happen with malformed AST or missing type information
240
+ }
241
+ }
242
+ /* c8 ignore stop */
243
+ // Without type information, treat all identifiers as potentially dangerous
244
+ return false;
245
+ };
246
+ /**
247
+ * Check if the property key has been validated before use.
248
+ *
249
+ * Detects patterns like:
250
+ * - if (ARRAY.includes(key)) { obj[key] = value; }
251
+ * - if (Object.prototype.hasOwnProperty.call(obj, key)) { return obj[key]; }
252
+ * - if (Object.hasOwn(obj, key)) { return obj[key]; }
253
+ *
254
+ * @param propertyNode - The property node (key in obj[key])
255
+ * @param node - The current node being checked
256
+ * @returns true if the key has been validated, false otherwise
257
+ */
258
+ const hasPrecedingValidation = (propertyNode, node) => {
259
+ // Only check for identifier keys (obj[key] where key is a variable)
260
+ if (propertyNode.type !== eslint_devkit_1.AST_NODE_TYPES.Identifier) {
261
+ return false;
262
+ }
263
+ const keyName = propertyNode.name;
264
+ // AST-based validation detection (faster than getText + regex)
265
+ const isIncludesCall = (testNode) => {
266
+ // Pattern: ARRAY.includes(keyName)
267
+ if (testNode.type === eslint_devkit_1.AST_NODE_TYPES.CallExpression &&
268
+ testNode.callee.type === eslint_devkit_1.AST_NODE_TYPES.MemberExpression &&
269
+ testNode.callee.property.type === eslint_devkit_1.AST_NODE_TYPES.Identifier &&
270
+ testNode.callee.property.name === 'includes' &&
271
+ testNode.arguments.length > 0 &&
272
+ testNode.arguments[0].type === eslint_devkit_1.AST_NODE_TYPES.Identifier &&
273
+ testNode.arguments[0].name === keyName) {
274
+ return true;
275
+ }
276
+ // Handle negation: !ARRAY.includes(key)
277
+ if (testNode.type === eslint_devkit_1.AST_NODE_TYPES.UnaryExpression &&
278
+ testNode.operator === '!' &&
279
+ testNode.argument.type === eslint_devkit_1.AST_NODE_TYPES.CallExpression) {
280
+ return isIncludesCall(testNode.argument);
281
+ }
282
+ return false;
283
+ };
284
+ const isHasOwnPropertyCall = (testNode) => {
285
+ // Pattern: Object.prototype.hasOwnProperty.call(obj, key) OR obj.hasOwnProperty(key) OR Object.hasOwn(obj, key)
286
+ if (testNode.type !== eslint_devkit_1.AST_NODE_TYPES.CallExpression)
287
+ return false;
288
+ const callee = testNode.callee;
289
+ const args = testNode.arguments;
290
+ // Object.prototype.hasOwnProperty.call(obj, key)
291
+ if (callee.type === eslint_devkit_1.AST_NODE_TYPES.MemberExpression &&
292
+ callee.property.type === eslint_devkit_1.AST_NODE_TYPES.Identifier &&
293
+ callee.property.name === 'call' &&
294
+ args.length >= 2 &&
295
+ args[1].type === eslint_devkit_1.AST_NODE_TYPES.Identifier &&
296
+ args[1].name === keyName) {
297
+ return true;
298
+ }
299
+ // obj.hasOwnProperty(key) OR Object.hasOwn(obj, key)
300
+ if (callee.type === eslint_devkit_1.AST_NODE_TYPES.MemberExpression &&
301
+ callee.property.type === eslint_devkit_1.AST_NODE_TYPES.Identifier &&
302
+ (callee.property.name === 'hasOwnProperty' || callee.property.name === 'hasOwn')) {
303
+ const keyArg = callee.property.name === 'hasOwn' ? args[1] : args[0];
304
+ if (keyArg?.type === eslint_devkit_1.AST_NODE_TYPES.Identifier && keyArg.name === keyName) {
305
+ return true;
306
+ }
307
+ }
308
+ return false;
309
+ };
310
+ const isInOperator = (testNode) => {
311
+ // Pattern: key in obj
312
+ return testNode.type === eslint_devkit_1.AST_NODE_TYPES.BinaryExpression &&
313
+ testNode.operator === 'in' &&
314
+ testNode.left.type === eslint_devkit_1.AST_NODE_TYPES.Identifier &&
315
+ testNode.left.name === keyName;
316
+ };
317
+ const hasValidation = (testNode) => {
318
+ return isIncludesCall(testNode) || isHasOwnPropertyCall(testNode) || isInOperator(testNode);
319
+ };
320
+ const hasEarlyExit = (consequent) => {
321
+ // Check if block contains throw or return
322
+ if (consequent.type === eslint_devkit_1.AST_NODE_TYPES.BlockStatement) {
323
+ return consequent.body.some(stmt => stmt.type === eslint_devkit_1.AST_NODE_TYPES.ThrowStatement ||
324
+ stmt.type === eslint_devkit_1.AST_NODE_TYPES.ReturnStatement);
325
+ }
326
+ return consequent.type === eslint_devkit_1.AST_NODE_TYPES.ThrowStatement ||
327
+ consequent.type === eslint_devkit_1.AST_NODE_TYPES.ReturnStatement;
328
+ };
329
+ // Walk up to find enclosing IfStatement with validation
330
+ let current = node.parent;
331
+ let foundFunctionBody = false;
332
+ while (current && !foundFunctionBody) {
333
+ // Check if we're inside an if-block with validation in the condition
334
+ if (current.type === eslint_devkit_1.AST_NODE_TYPES.IfStatement) {
335
+ if (hasValidation(current.test)) {
336
+ return true;
337
+ }
338
+ }
339
+ // Check for function body - look for preceding sibling if-statements with early exit
340
+ if (current.type === eslint_devkit_1.AST_NODE_TYPES.BlockStatement && current.parent && (current.parent.type === eslint_devkit_1.AST_NODE_TYPES.FunctionDeclaration ||
341
+ current.parent.type === eslint_devkit_1.AST_NODE_TYPES.FunctionExpression ||
342
+ current.parent.type === eslint_devkit_1.AST_NODE_TYPES.ArrowFunctionExpression)) {
343
+ foundFunctionBody = true;
344
+ const blockBody = current.body;
345
+ const nodeIndex = blockBody.findIndex((stmt) => {
346
+ let check = node;
347
+ while (check) {
348
+ if (check === stmt)
349
+ return true;
350
+ check = check.parent;
351
+ }
352
+ return false;
353
+ });
354
+ // Look at preceding statements for validation patterns with early exit
355
+ for (let i = 0; i < nodeIndex; i++) {
356
+ const stmt = blockBody[i];
357
+ if (stmt.type === eslint_devkit_1.AST_NODE_TYPES.IfStatement &&
358
+ hasValidation(stmt.test) &&
359
+ hasEarlyExit(stmt.consequent)) {
360
+ return true;
361
+ }
362
+ }
363
+ }
364
+ current = current.parent;
365
+ }
366
+ return false;
367
+ };
368
+ /**
369
+ * Check if property access is potentially dangerous
370
+ */
371
+ const isDangerousPropertyAccess = (propertyNode) => {
372
+ // SAFE: Numeric literals (array index access like items[0], items[1])
373
+ if (propertyNode.type === eslint_devkit_1.AST_NODE_TYPES.Literal && typeof propertyNode.value === 'number') {
374
+ return false;
375
+ }
376
+ // Check if it's a literal string first
377
+ if (isLiteralString(propertyNode)) {
378
+ const propName = String(propertyNode.value);
379
+ // DANGEROUS: Literal strings that match dangerous properties (always flag these)
380
+ // Check this BEFORE checking typed union access
381
+ if (dangerousProperties.includes(propName)) {
382
+ return true;
383
+ }
384
+ // SAFE: Typed union access (obj[typedKey] where typedKey is 'primary' | 'secondary')
385
+ // Only safe if it's NOT a dangerous property
386
+ if (isTypedUnionAccess(propertyNode)) {
387
+ return false;
388
+ }
389
+ // SAFE: Literal strings that are NOT dangerous properties (if allowLiterals is true)
390
+ if (allowLiterals) {
391
+ return false;
392
+ }
393
+ // If allowLiterals is false, non-dangerous literal strings are still considered safe
394
+ // (they're static and known at compile time)
395
+ return false;
396
+ }
397
+ // DANGEROUS: Any untyped/dynamic property access (e.g., obj[userInput])
398
+ return true;
399
+ };
400
+ /**
401
+ * Extract property access information
402
+ */
403
+ const extractPropertyAccess = (node) => {
404
+ const sourceCode = context.sourceCode || context.sourceCode;
405
+ let object;
406
+ let property;
407
+ let propertyNode;
408
+ let isAssignment = false;
409
+ if (node.type === eslint_devkit_1.AST_NODE_TYPES.AssignmentExpression && node.left.type === eslint_devkit_1.AST_NODE_TYPES.MemberExpression) {
410
+ // Assignment: obj[key] = value
411
+ object = sourceCode.getText(node.left.object);
412
+ property = sourceCode.getText(node.left.property);
413
+ propertyNode = node.left.property;
414
+ isAssignment = true;
415
+ }
416
+ else if (node.type === eslint_devkit_1.AST_NODE_TYPES.MemberExpression) {
417
+ // Access: obj[key]
418
+ object = sourceCode.getText(node.object);
419
+ property = sourceCode.getText(node.property);
420
+ propertyNode = node.property;
421
+ isAssignment = false;
422
+ }
423
+ else {
424
+ return { object: '', property: '', propertyNode: node, isAssignment: false, pattern: null };
425
+ }
426
+ // Check if property matches dangerous patterns
427
+ const pattern = OBJECT_INJECTION_PATTERNS.find(p => new RegExp(p.pattern, 'i').test(property) ||
428
+ dangerousProperties.includes(property.replace(/['"]/g, ''))) || null;
429
+ return { object, property, propertyNode, isAssignment, pattern };
430
+ };
431
+ /**
432
+ * Determine if this is a high-risk assignment
433
+ */
434
+ const isHighRiskAssignment = (node) => {
435
+ if (node.left.type !== 'MemberExpression') {
436
+ return false;
437
+ }
438
+ // Only check computed member access (bracket notation)
439
+ // Dot notation (obj.name) is safe
440
+ if (!node.left.computed) {
441
+ return false;
442
+ }
443
+ const { propertyNode } = extractPropertyAccess(node);
444
+ // Skip if the key has been validated (e.g., includes() or hasOwnProperty check)
445
+ if (hasPrecedingValidation(propertyNode, node)) {
446
+ return false;
447
+ }
448
+ // Check for dangerous property access in assignment
449
+ return isDangerousPropertyAccess(propertyNode);
450
+ };
451
+ /**
452
+ * Determine if this is a high-risk member access
453
+ */
454
+ const isHighRiskMemberAccess = (node) => {
455
+ // Only check computed member access (bracket notation)
456
+ if (!node.computed) {
457
+ return false;
458
+ }
459
+ const { propertyNode } = extractPropertyAccess(node);
460
+ // Skip if the key has been validated (e.g., includes() or hasOwnProperty check)
461
+ if (hasPrecedingValidation(propertyNode, node)) {
462
+ return false;
463
+ }
464
+ // Check for dangerous property access
465
+ return isDangerousPropertyAccess(propertyNode);
466
+ };
467
+ /**
468
+ * Determine risk level based on the pattern and context
469
+ */
470
+ const determineRiskLevel = (pattern, isAssignment) => {
471
+ if (pattern?.riskLevel === 'critical' || (pattern && isAssignment)) {
472
+ return 'CRITICAL';
473
+ }
474
+ if (pattern?.riskLevel === 'high' || isAssignment) {
475
+ return 'HIGH';
476
+ }
477
+ return 'MEDIUM';
478
+ };
479
+ /**
480
+ * Check assignment expressions for object injection
481
+ */
482
+ const checkAssignmentExpression = (node) => {
483
+ if (!isHighRiskAssignment(node)) {
484
+ return;
485
+ }
486
+ // Mark the MemberExpression as handled to avoid double-reporting
487
+ if (node.left.type === eslint_devkit_1.AST_NODE_TYPES.MemberExpression) {
488
+ handledMemberExpressions.add(node.left);
489
+ }
490
+ const { object, property, isAssignment, pattern } = extractPropertyAccess(node);
491
+ const riskLevel = determineRiskLevel(pattern, isAssignment);
492
+ context.report({
493
+ node,
494
+ messageId: 'objectInjection',
495
+ data: {
496
+ pattern: `${object}[${property}]`,
497
+ riskLevel,
498
+ vulnerability: pattern?.vulnerability || 'object injection',
499
+ safeAlternative: pattern?.safeAlternative || 'Use Map or property whitelisting',
500
+ },
501
+ suggest: [
502
+ {
503
+ messageId: 'useMapInstead',
504
+ fix: () => null
505
+ },
506
+ {
507
+ messageId: 'useHasOwnProperty',
508
+ fix: () => null
509
+ },
510
+ {
511
+ messageId: 'whitelistKeys',
512
+ fix: () => null
513
+ },
514
+ {
515
+ messageId: 'useObjectCreate',
516
+ fix: () => null
517
+ },
518
+ {
519
+ messageId: 'freezePrototypes',
520
+ fix: () => null
521
+ }
522
+ ]
523
+ });
524
+ };
525
+ /**
526
+ * Check member expressions for object injection
527
+ */
528
+ const checkMemberExpression = (node) => {
529
+ if (!isHighRiskMemberAccess(node)) {
530
+ return;
531
+ }
532
+ // Skip if this MemberExpression was already handled as part of an AssignmentExpression
533
+ if (handledMemberExpressions.has(node)) {
534
+ return;
535
+ }
536
+ // Also check parent - if it's an AssignmentExpression and this node is the left side, skip
537
+ // (This handles cases where WeakSet check didn't work due to visitor order)
538
+ const parent = node.parent;
539
+ if (parent && parent.type === eslint_devkit_1.AST_NODE_TYPES.AssignmentExpression && parent.left === node) {
540
+ return;
541
+ }
542
+ const { object, property, isAssignment, pattern } = extractPropertyAccess(node);
543
+ const riskLevel = determineRiskLevel(pattern, isAssignment);
544
+ context.report({
545
+ node,
546
+ messageId: 'objectInjection',
547
+ data: {
548
+ pattern: `${object}[${property}]`,
549
+ riskLevel,
550
+ vulnerability: pattern?.vulnerability || 'object injection',
551
+ safeAlternative: pattern?.safeAlternative || 'Use Map or property whitelisting',
552
+ }
553
+ });
554
+ };
555
+ return {
556
+ AssignmentExpression: checkAssignmentExpression,
557
+ MemberExpression: checkMemberExpression
558
+ };
559
+ },
560
+ });
@@ -0,0 +1,8 @@
1
+ /**
2
+ * @fileoverview Detect potential typosquatting in dependencies
3
+ * @see https://owasp.org/www-project-mobile-top-10/
4
+ * @see https://cwe.mitre.org/data/definitions/506.html
5
+ */
6
+ export interface Options {
7
+ }
8
+ export declare const detectSuspiciousDependencies: ESLintUtils.RuleModule<MessageIds, Options, unknown, ESLintUtils.RuleListener>;
@@ -0,0 +1,71 @@
1
+ "use strict";
2
+ /**
3
+ * @fileoverview Detect potential typosquatting in dependencies
4
+ * @see https://owasp.org/www-project-mobile-top-10/
5
+ * @see https://cwe.mitre.org/data/definitions/506.html
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.detectSuspiciousDependencies = void 0;
9
+ const eslint_devkit_1 = require("@interlace/eslint-devkit");
10
+ exports.detectSuspiciousDependencies = (0, eslint_devkit_1.createRule)({
11
+ name: 'detect-suspicious-dependencies',
12
+ meta: {
13
+ type: 'problem',
14
+ docs: {
15
+ description: 'Detect typosquatting in package names',
16
+ },
17
+ messages: {
18
+ violationDetected: (0, eslint_devkit_1.formatLLMMessage)({
19
+ icon: eslint_devkit_1.MessageIcons.SECURITY,
20
+ issueName: 'Suspicious Dependency',
21
+ cwe: 'CWE-506',
22
+ description: 'Suspicious package name detected - possible typosquatting',
23
+ severity: 'HIGH',
24
+ fix: 'Verify package authenticity on npm registry',
25
+ documentationLink: 'https://cwe.mitre.org/data/definitions/506.html',
26
+ })
27
+ },
28
+ schema: [],
29
+ },
30
+ defaultOptions: [],
31
+ create(context) {
32
+ const popularPackages = ['react', 'lodash', 'express', 'axios', 'webpack'];
33
+ function levenshtein(a, b) {
34
+ const matrix = [];
35
+ for (let i = 0; i <= b.length; i++) {
36
+ matrix[i] = [i];
37
+ }
38
+ for (let j = 0; j <= a.length; j++) {
39
+ matrix[0][j] = j;
40
+ }
41
+ for (let i = 1; i <= b.length; i++) {
42
+ for (let j = 1; j <= a.length; j++) {
43
+ if (b.charAt(i - 1) === a.charAt(j - 1)) {
44
+ matrix[i][j] = matrix[i - 1][j - 1];
45
+ }
46
+ else {
47
+ matrix[i][j] = Math.min(matrix[i - 1][j - 1] + 1, matrix[i][j - 1] + 1, matrix[i - 1][j] + 1);
48
+ }
49
+ }
50
+ }
51
+ return matrix[b.length][a.length];
52
+ }
53
+ return {
54
+ ImportDeclaration(node) {
55
+ const source = node.source.value;
56
+ if (typeof source === 'string' && !source.startsWith('.') && !source.startsWith('@')) {
57
+ for (const popular of popularPackages) {
58
+ const distance = levenshtein(source, popular);
59
+ if (distance > 0 && distance <= 2) {
60
+ context.report({
61
+ node,
62
+ messageId: 'violationDetected',
63
+ data: { name: source, similar: popular },
64
+ });
65
+ }
66
+ }
67
+ }
68
+ },
69
+ };
70
+ },
71
+ });
@@ -0,0 +1,6 @@
1
+ /**
2
+ * @fileoverview Identify weak password requirements
3
+ */
4
+ export interface Options {
5
+ }
6
+ export declare const detectWeakPasswordValidation: ESLintUtils.RuleModule<MessageIds, Options, unknown, ESLintUtils.RuleListener>;