eslint-plugin-secure-coding 2.3.2 → 2.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (361) hide show
  1. package/README.md +1 -0
  2. package/package.json +3 -10
  3. package/src/index.ts +605 -0
  4. package/src/rules/__tests__/integration-demo.test.ts +290 -0
  5. package/src/rules/__tests__/integration-llm.test.ts +89 -0
  6. package/src/rules/database-injection/database-injection.test.ts +456 -0
  7. package/src/rules/database-injection/index.ts +488 -0
  8. package/src/rules/detect-child-process/detect-child-process.test.ts +207 -0
  9. package/src/rules/detect-child-process/index.ts +634 -0
  10. package/src/rules/detect-eval-with-expression/detect-eval-with-expression.test.ts +416 -0
  11. package/src/rules/detect-eval-with-expression/index.ts +463 -0
  12. package/src/rules/detect-mixed-content/detect-mixed-content.test.ts +28 -0
  13. package/src/rules/detect-mixed-content/index.ts +52 -0
  14. package/src/rules/detect-non-literal-fs-filename/detect-non-literal-fs-filename.test.ts +269 -0
  15. package/src/rules/detect-non-literal-fs-filename/index.ts +551 -0
  16. package/src/rules/detect-non-literal-regexp/detect-non-literal-regexp.test.ts +189 -0
  17. package/src/rules/detect-non-literal-regexp/index.ts +490 -0
  18. package/src/rules/detect-object-injection/detect-object-injection.test.ts +440 -0
  19. package/src/rules/detect-object-injection/index.ts +674 -0
  20. package/src/rules/detect-suspicious-dependencies/detect-suspicious-dependencies.test.ts +32 -0
  21. package/src/rules/detect-suspicious-dependencies/index.ts +84 -0
  22. package/src/rules/detect-weak-password-validation/detect-weak-password-validation.test.ts +31 -0
  23. package/src/rules/detect-weak-password-validation/index.ts +68 -0
  24. package/src/rules/no-allow-arbitrary-loads/index.ts +54 -0
  25. package/src/rules/no-allow-arbitrary-loads/no-allow-arbitrary-loads.test.ts +28 -0
  26. package/src/rules/no-arbitrary-file-access/index.ts +238 -0
  27. package/src/rules/no-arbitrary-file-access/no-arbitrary-file-access.test.ts +119 -0
  28. package/src/rules/no-buffer-overread/index.ts +724 -0
  29. package/src/rules/no-buffer-overread/no-buffer-overread.test.ts +313 -0
  30. package/src/rules/no-clickjacking/index.ts +481 -0
  31. package/src/rules/no-clickjacking/no-clickjacking.test.ts +253 -0
  32. package/src/rules/no-client-side-auth-logic/index.ts +81 -0
  33. package/src/rules/no-client-side-auth-logic/no-client-side-auth-logic.test.ts +33 -0
  34. package/src/rules/no-credentials-in-query-params/index.ts +69 -0
  35. package/src/rules/no-credentials-in-query-params/no-credentials-in-query-params.test.ts +33 -0
  36. package/src/rules/no-credentials-in-storage-api/index.ts +64 -0
  37. package/src/rules/no-credentials-in-storage-api/no-credentials-in-storage-api.test.ts +31 -0
  38. package/src/rules/no-data-in-temp-storage/index.ts +75 -0
  39. package/src/rules/no-data-in-temp-storage/no-data-in-temp-storage.test.ts +33 -0
  40. package/src/rules/no-debug-code-in-production/index.ts +59 -0
  41. package/src/rules/no-debug-code-in-production/no-debug-code-in-production.test.ts +26 -0
  42. package/src/rules/no-directive-injection/index.ts +551 -0
  43. package/src/rules/no-directive-injection/no-directive-injection.test.ts +305 -0
  44. package/src/rules/no-disabled-certificate-validation/index.ts +72 -0
  45. package/src/rules/no-disabled-certificate-validation/no-disabled-certificate-validation.test.ts +33 -0
  46. package/src/rules/no-document-cookie/index.ts +113 -0
  47. package/src/rules/no-document-cookie/no-document-cookie.test.ts +382 -0
  48. package/src/rules/no-dynamic-dependency-loading/index.ts +60 -0
  49. package/src/rules/no-dynamic-dependency-loading/no-dynamic-dependency-loading.test.ts +27 -0
  50. package/src/rules/no-electron-security-issues/index.ts +504 -0
  51. package/src/rules/no-electron-security-issues/no-electron-security-issues.test.ts +324 -0
  52. package/src/rules/no-exposed-debug-endpoints/index.ts +73 -0
  53. package/src/rules/no-exposed-debug-endpoints/no-exposed-debug-endpoints.test.ts +40 -0
  54. package/src/rules/no-exposed-sensitive-data/index.ts +428 -0
  55. package/src/rules/no-exposed-sensitive-data/no-exposed-sensitive-data.test.ts +75 -0
  56. package/src/rules/no-format-string-injection/index.ts +801 -0
  57. package/src/rules/no-format-string-injection/no-format-string-injection.test.ts +437 -0
  58. package/src/rules/no-graphql-injection/index.ts +508 -0
  59. package/src/rules/no-graphql-injection/no-graphql-injection.test.ts +371 -0
  60. package/src/rules/no-hardcoded-credentials/index.ts +478 -0
  61. package/src/rules/no-hardcoded-credentials/no-hardcoded-credentials.test.ts +639 -0
  62. package/src/rules/no-hardcoded-session-tokens/index.ts +69 -0
  63. package/src/rules/no-hardcoded-session-tokens/no-hardcoded-session-tokens.test.ts +42 -0
  64. package/src/rules/no-http-urls/index.ts +131 -0
  65. package/src/rules/no-http-urls/no-http-urls.test.ts +60 -0
  66. package/src/rules/no-improper-sanitization/index.ts +502 -0
  67. package/src/rules/no-improper-sanitization/no-improper-sanitization.test.ts +156 -0
  68. package/src/rules/no-improper-type-validation/index.ts +572 -0
  69. package/src/rules/no-improper-type-validation/no-improper-type-validation.test.ts +372 -0
  70. package/src/rules/no-insecure-comparison/index.ts +232 -0
  71. package/src/rules/no-insecure-comparison/no-insecure-comparison.test.ts +218 -0
  72. package/src/rules/no-insecure-cookie-settings/index.ts +391 -0
  73. package/src/rules/no-insecure-cookie-settings/no-insecure-cookie-settings.test.ts +409 -0
  74. package/src/rules/no-insecure-jwt/index.ts +467 -0
  75. package/src/rules/no-insecure-jwt/no-insecure-jwt.test.ts +259 -0
  76. package/src/rules/no-insecure-redirects/index.ts +267 -0
  77. package/src/rules/no-insecure-redirects/no-insecure-redirects.test.ts +108 -0
  78. package/src/rules/no-insecure-websocket/index.ts +72 -0
  79. package/src/rules/no-insecure-websocket/no-insecure-websocket.test.ts +42 -0
  80. package/src/rules/no-insufficient-postmessage-validation/index.ts +497 -0
  81. package/src/rules/no-insufficient-postmessage-validation/no-insufficient-postmessage-validation.test.ts +360 -0
  82. package/src/rules/no-insufficient-random/index.ts +288 -0
  83. package/src/rules/no-insufficient-random/no-insufficient-random.test.ts +246 -0
  84. package/src/rules/no-ldap-injection/index.ts +547 -0
  85. package/src/rules/no-ldap-injection/no-ldap-injection.test.ts +317 -0
  86. package/src/rules/no-missing-authentication/index.ts +408 -0
  87. package/src/rules/no-missing-authentication/no-missing-authentication.test.ts +350 -0
  88. package/src/rules/no-missing-cors-check/index.ts +453 -0
  89. package/src/rules/no-missing-cors-check/no-missing-cors-check.test.ts +392 -0
  90. package/src/rules/no-missing-csrf-protection/index.ts +229 -0
  91. package/src/rules/no-missing-csrf-protection/no-missing-csrf-protection.test.ts +222 -0
  92. package/src/rules/no-missing-security-headers/index.ts +266 -0
  93. package/src/rules/no-missing-security-headers/no-missing-security-headers.test.ts +98 -0
  94. package/src/rules/no-password-in-url/index.ts +64 -0
  95. package/src/rules/no-password-in-url/no-password-in-url.test.ts +27 -0
  96. package/src/rules/no-permissive-cors/index.ts +78 -0
  97. package/src/rules/no-permissive-cors/no-permissive-cors.test.ts +28 -0
  98. package/src/rules/no-pii-in-logs/index.ts +83 -0
  99. package/src/rules/no-pii-in-logs/no-pii-in-logs.test.ts +26 -0
  100. package/src/rules/no-postmessage-origin-wildcard/index.ts +67 -0
  101. package/src/rules/no-postmessage-origin-wildcard/no-postmessage-origin-wildcard.test.ts +27 -0
  102. package/src/rules/no-privilege-escalation/index.ts +403 -0
  103. package/src/rules/no-privilege-escalation/no-privilege-escalation.test.ts +306 -0
  104. package/src/rules/no-redos-vulnerable-regex/index.ts +379 -0
  105. package/src/rules/no-redos-vulnerable-regex/no-redos-vulnerable-regex.test.ts +83 -0
  106. package/src/rules/no-sensitive-data-exposure/index.ts +294 -0
  107. package/src/rules/no-sensitive-data-exposure/no-sensitive-data-exposure.test.ts +262 -0
  108. package/src/rules/no-sensitive-data-in-analytics/index.ts +73 -0
  109. package/src/rules/no-sensitive-data-in-analytics/no-sensitive-data-in-analytics.test.ts +42 -0
  110. package/src/rules/no-sensitive-data-in-cache/index.ts +59 -0
  111. package/src/rules/no-sensitive-data-in-cache/no-sensitive-data-in-cache.test.ts +32 -0
  112. package/src/rules/no-sql-injection/index.ts +424 -0
  113. package/src/rules/no-sql-injection/no-sql-injection.test.ts +303 -0
  114. package/src/rules/no-timing-attack/index.ts +552 -0
  115. package/src/rules/no-timing-attack/no-timing-attack.test.ts +348 -0
  116. package/src/rules/no-toctou-vulnerability/index.ts +250 -0
  117. package/src/rules/no-toctou-vulnerability/no-toctou-vulnerability.test.ts +60 -0
  118. package/src/rules/no-tracking-without-consent/index.ts +78 -0
  119. package/src/rules/no-tracking-without-consent/no-tracking-without-consent.test.ts +34 -0
  120. package/src/rules/no-unchecked-loop-condition/index.ts +781 -0
  121. package/src/rules/no-unchecked-loop-condition/no-unchecked-loop-condition.test.ts +459 -0
  122. package/src/rules/no-unencrypted-local-storage/index.ts +73 -0
  123. package/src/rules/no-unencrypted-local-storage/no-unencrypted-local-storage.test.ts +41 -0
  124. package/src/rules/no-unencrypted-transmission/index.ts +296 -0
  125. package/src/rules/no-unencrypted-transmission/no-unencrypted-transmission.test.ts +287 -0
  126. package/src/rules/no-unescaped-url-parameter/index.ts +424 -0
  127. package/src/rules/no-unescaped-url-parameter/no-unescaped-url-parameter.test.ts +263 -0
  128. package/src/rules/no-unlimited-resource-allocation/index.ts +767 -0
  129. package/src/rules/no-unlimited-resource-allocation/no-unlimited-resource-allocation.test.ts +544 -0
  130. package/src/rules/no-unsafe-deserialization/index.ts +593 -0
  131. package/src/rules/no-unsafe-deserialization/no-unsafe-deserialization.test.ts +310 -0
  132. package/src/rules/no-unsafe-dynamic-require/index.ts +125 -0
  133. package/src/rules/no-unsafe-dynamic-require/no-unsafe-dynamic-require.test.ts +151 -0
  134. package/src/rules/no-unsafe-regex-construction/index.ts +370 -0
  135. package/src/rules/no-unsafe-regex-construction/no-unsafe-regex-construction.test.ts +181 -0
  136. package/src/rules/no-unsanitized-html/index.ts +400 -0
  137. package/src/rules/no-unsanitized-html/no-unsanitized-html.test.ts +488 -0
  138. package/src/rules/no-unvalidated-deeplinks/index.ts +73 -0
  139. package/src/rules/no-unvalidated-deeplinks/no-unvalidated-deeplinks.test.ts +29 -0
  140. package/src/rules/no-unvalidated-user-input/index.ts +498 -0
  141. package/src/rules/no-unvalidated-user-input/no-unvalidated-user-input.test.ts +463 -0
  142. package/src/rules/no-verbose-error-messages/index.ts +83 -0
  143. package/src/rules/no-verbose-error-messages/no-verbose-error-messages.test.ts +34 -0
  144. package/src/rules/no-weak-crypto/index.ts +447 -0
  145. package/src/rules/no-weak-crypto/no-weak-crypto.test.ts +297 -0
  146. package/src/rules/no-weak-password-recovery/index.ts +509 -0
  147. package/src/rules/no-weak-password-recovery/no-weak-password-recovery.test.ts +184 -0
  148. package/src/rules/no-xpath-injection/index.ts +596 -0
  149. package/src/rules/no-xpath-injection/no-xpath-injection.test.ts +405 -0
  150. package/src/rules/no-xxe-injection/index.ts +342 -0
  151. package/src/rules/no-xxe-injection/no-xxe-injection.test.ts +122 -0
  152. package/src/rules/no-zip-slip/index.ts +526 -0
  153. package/src/rules/no-zip-slip/no-zip-slip.test.ts +305 -0
  154. package/src/rules/require-backend-authorization/index.ts +71 -0
  155. package/src/rules/require-backend-authorization/require-backend-authorization.test.ts +31 -0
  156. package/src/rules/require-code-minification/index.ts +54 -0
  157. package/src/rules/require-code-minification/require-code-minification.test.ts +30 -0
  158. package/src/rules/require-csp-headers/index.ts +74 -0
  159. package/src/rules/require-csp-headers/require-csp-headers.test.ts +34 -0
  160. package/src/rules/require-data-minimization/index.ts +65 -0
  161. package/src/rules/require-data-minimization/require-data-minimization.test.ts +31 -0
  162. package/src/rules/require-dependency-integrity/index.ts +78 -0
  163. package/src/rules/require-dependency-integrity/require-dependency-integrity.test.ts +44 -0
  164. package/src/rules/require-https-only/index.ts +75 -0
  165. package/src/rules/require-https-only/require-https-only.test.ts +26 -0
  166. package/src/rules/require-mime-type-validation/index.ts +77 -0
  167. package/src/rules/require-mime-type-validation/require-mime-type-validation.test.ts +32 -0
  168. package/src/rules/require-network-timeout/index.ts +58 -0
  169. package/src/rules/require-network-timeout/require-network-timeout.test.ts +26 -0
  170. package/src/rules/require-package-lock/index.ts +75 -0
  171. package/src/rules/require-package-lock/require-package-lock.test.ts +27 -0
  172. package/src/rules/require-secure-credential-storage/index.ts +60 -0
  173. package/src/rules/require-secure-credential-storage/require-secure-credential-storage.test.ts +26 -0
  174. package/src/rules/require-secure-defaults/index.ts +54 -0
  175. package/src/rules/require-secure-defaults/require-secure-defaults.test.ts +26 -0
  176. package/src/rules/require-secure-deletion/index.ts +52 -0
  177. package/src/rules/require-secure-deletion/require-secure-deletion.test.ts +29 -0
  178. package/src/rules/require-storage-encryption/index.ts +60 -0
  179. package/src/rules/require-storage-encryption/require-storage-encryption.test.ts +26 -0
  180. package/src/rules/require-url-validation/index.ts +85 -0
  181. package/src/rules/require-url-validation/require-url-validation.test.ts +32 -0
  182. package/src/types/{index.d.ts → index.ts} +157 -53
  183. package/src/index.d.ts +0 -32
  184. package/src/index.js +0 -465
  185. package/src/rules/database-injection/index.d.ts +0 -13
  186. package/src/rules/database-injection/index.js +0 -406
  187. package/src/rules/detect-child-process/index.d.ts +0 -11
  188. package/src/rules/detect-child-process/index.js +0 -529
  189. package/src/rules/detect-eval-with-expression/index.d.ts +0 -9
  190. package/src/rules/detect-eval-with-expression/index.js +0 -392
  191. package/src/rules/detect-mixed-content/index.d.ts +0 -8
  192. package/src/rules/detect-mixed-content/index.js +0 -44
  193. package/src/rules/detect-non-literal-fs-filename/index.d.ts +0 -7
  194. package/src/rules/detect-non-literal-fs-filename/index.js +0 -454
  195. package/src/rules/detect-non-literal-regexp/index.d.ts +0 -9
  196. package/src/rules/detect-non-literal-regexp/index.js +0 -403
  197. package/src/rules/detect-object-injection/index.d.ts +0 -11
  198. package/src/rules/detect-object-injection/index.js +0 -560
  199. package/src/rules/detect-suspicious-dependencies/index.d.ts +0 -8
  200. package/src/rules/detect-suspicious-dependencies/index.js +0 -71
  201. package/src/rules/detect-weak-password-validation/index.d.ts +0 -6
  202. package/src/rules/detect-weak-password-validation/index.js +0 -58
  203. package/src/rules/no-allow-arbitrary-loads/index.d.ts +0 -8
  204. package/src/rules/no-allow-arbitrary-loads/index.js +0 -47
  205. package/src/rules/no-arbitrary-file-access/index.d.ts +0 -13
  206. package/src/rules/no-arbitrary-file-access/index.js +0 -195
  207. package/src/rules/no-buffer-overread/index.d.ts +0 -29
  208. package/src/rules/no-buffer-overread/index.js +0 -606
  209. package/src/rules/no-clickjacking/index.d.ts +0 -10
  210. package/src/rules/no-clickjacking/index.js +0 -396
  211. package/src/rules/no-client-side-auth-logic/index.d.ts +0 -6
  212. package/src/rules/no-client-side-auth-logic/index.js +0 -69
  213. package/src/rules/no-credentials-in-query-params/index.d.ts +0 -8
  214. package/src/rules/no-credentials-in-query-params/index.js +0 -57
  215. package/src/rules/no-credentials-in-storage-api/index.d.ts +0 -6
  216. package/src/rules/no-credentials-in-storage-api/index.js +0 -54
  217. package/src/rules/no-data-in-temp-storage/index.d.ts +0 -6
  218. package/src/rules/no-data-in-temp-storage/index.js +0 -64
  219. package/src/rules/no-debug-code-in-production/index.d.ts +0 -8
  220. package/src/rules/no-debug-code-in-production/index.js +0 -51
  221. package/src/rules/no-directive-injection/index.d.ts +0 -12
  222. package/src/rules/no-directive-injection/index.js +0 -457
  223. package/src/rules/no-disabled-certificate-validation/index.d.ts +0 -6
  224. package/src/rules/no-disabled-certificate-validation/index.js +0 -61
  225. package/src/rules/no-document-cookie/index.d.ts +0 -5
  226. package/src/rules/no-document-cookie/index.js +0 -89
  227. package/src/rules/no-dynamic-dependency-loading/index.d.ts +0 -8
  228. package/src/rules/no-dynamic-dependency-loading/index.js +0 -51
  229. package/src/rules/no-electron-security-issues/index.d.ts +0 -10
  230. package/src/rules/no-electron-security-issues/index.js +0 -423
  231. package/src/rules/no-exposed-debug-endpoints/index.d.ts +0 -6
  232. package/src/rules/no-exposed-debug-endpoints/index.js +0 -62
  233. package/src/rules/no-exposed-sensitive-data/index.d.ts +0 -11
  234. package/src/rules/no-exposed-sensitive-data/index.js +0 -340
  235. package/src/rules/no-format-string-injection/index.d.ts +0 -17
  236. package/src/rules/no-format-string-injection/index.js +0 -660
  237. package/src/rules/no-graphql-injection/index.d.ts +0 -12
  238. package/src/rules/no-graphql-injection/index.js +0 -411
  239. package/src/rules/no-hardcoded-credentials/index.d.ts +0 -26
  240. package/src/rules/no-hardcoded-credentials/index.js +0 -376
  241. package/src/rules/no-hardcoded-session-tokens/index.d.ts +0 -6
  242. package/src/rules/no-hardcoded-session-tokens/index.js +0 -59
  243. package/src/rules/no-http-urls/index.d.ts +0 -12
  244. package/src/rules/no-http-urls/index.js +0 -114
  245. package/src/rules/no-improper-sanitization/index.d.ts +0 -12
  246. package/src/rules/no-improper-sanitization/index.js +0 -411
  247. package/src/rules/no-improper-type-validation/index.d.ts +0 -10
  248. package/src/rules/no-improper-type-validation/index.js +0 -475
  249. package/src/rules/no-insecure-comparison/index.d.ts +0 -7
  250. package/src/rules/no-insecure-comparison/index.js +0 -193
  251. package/src/rules/no-insecure-cookie-settings/index.d.ts +0 -9
  252. package/src/rules/no-insecure-cookie-settings/index.js +0 -306
  253. package/src/rules/no-insecure-jwt/index.d.ts +0 -10
  254. package/src/rules/no-insecure-jwt/index.js +0 -380
  255. package/src/rules/no-insecure-redirects/index.d.ts +0 -7
  256. package/src/rules/no-insecure-redirects/index.js +0 -216
  257. package/src/rules/no-insecure-websocket/index.d.ts +0 -6
  258. package/src/rules/no-insecure-websocket/index.js +0 -61
  259. package/src/rules/no-insufficient-postmessage-validation/index.d.ts +0 -14
  260. package/src/rules/no-insufficient-postmessage-validation/index.js +0 -392
  261. package/src/rules/no-insufficient-random/index.d.ts +0 -9
  262. package/src/rules/no-insufficient-random/index.js +0 -208
  263. package/src/rules/no-ldap-injection/index.d.ts +0 -10
  264. package/src/rules/no-ldap-injection/index.js +0 -455
  265. package/src/rules/no-missing-authentication/index.d.ts +0 -13
  266. package/src/rules/no-missing-authentication/index.js +0 -333
  267. package/src/rules/no-missing-cors-check/index.d.ts +0 -9
  268. package/src/rules/no-missing-cors-check/index.js +0 -399
  269. package/src/rules/no-missing-csrf-protection/index.d.ts +0 -11
  270. package/src/rules/no-missing-csrf-protection/index.js +0 -180
  271. package/src/rules/no-missing-security-headers/index.d.ts +0 -7
  272. package/src/rules/no-missing-security-headers/index.js +0 -218
  273. package/src/rules/no-password-in-url/index.d.ts +0 -8
  274. package/src/rules/no-password-in-url/index.js +0 -54
  275. package/src/rules/no-permissive-cors/index.d.ts +0 -8
  276. package/src/rules/no-permissive-cors/index.js +0 -65
  277. package/src/rules/no-pii-in-logs/index.d.ts +0 -8
  278. package/src/rules/no-pii-in-logs/index.js +0 -70
  279. package/src/rules/no-postmessage-origin-wildcard/index.d.ts +0 -8
  280. package/src/rules/no-postmessage-origin-wildcard/index.js +0 -56
  281. package/src/rules/no-privilege-escalation/index.d.ts +0 -13
  282. package/src/rules/no-privilege-escalation/index.js +0 -321
  283. package/src/rules/no-redos-vulnerable-regex/index.d.ts +0 -7
  284. package/src/rules/no-redos-vulnerable-regex/index.js +0 -306
  285. package/src/rules/no-sensitive-data-exposure/index.d.ts +0 -11
  286. package/src/rules/no-sensitive-data-exposure/index.js +0 -250
  287. package/src/rules/no-sensitive-data-in-analytics/index.d.ts +0 -8
  288. package/src/rules/no-sensitive-data-in-analytics/index.js +0 -62
  289. package/src/rules/no-sensitive-data-in-cache/index.d.ts +0 -8
  290. package/src/rules/no-sensitive-data-in-cache/index.js +0 -52
  291. package/src/rules/no-sql-injection/index.d.ts +0 -10
  292. package/src/rules/no-sql-injection/index.js +0 -335
  293. package/src/rules/no-timing-attack/index.d.ts +0 -10
  294. package/src/rules/no-timing-attack/index.js +0 -447
  295. package/src/rules/no-toctou-vulnerability/index.d.ts +0 -7
  296. package/src/rules/no-toctou-vulnerability/index.js +0 -208
  297. package/src/rules/no-tracking-without-consent/index.d.ts +0 -6
  298. package/src/rules/no-tracking-without-consent/index.js +0 -67
  299. package/src/rules/no-unchecked-loop-condition/index.d.ts +0 -12
  300. package/src/rules/no-unchecked-loop-condition/index.js +0 -646
  301. package/src/rules/no-unencrypted-local-storage/index.d.ts +0 -8
  302. package/src/rules/no-unencrypted-local-storage/index.js +0 -61
  303. package/src/rules/no-unencrypted-transmission/index.d.ts +0 -11
  304. package/src/rules/no-unencrypted-transmission/index.js +0 -236
  305. package/src/rules/no-unescaped-url-parameter/index.d.ts +0 -9
  306. package/src/rules/no-unescaped-url-parameter/index.js +0 -355
  307. package/src/rules/no-unlimited-resource-allocation/index.d.ts +0 -12
  308. package/src/rules/no-unlimited-resource-allocation/index.js +0 -643
  309. package/src/rules/no-unsafe-deserialization/index.d.ts +0 -10
  310. package/src/rules/no-unsafe-deserialization/index.js +0 -491
  311. package/src/rules/no-unsafe-dynamic-require/index.d.ts +0 -5
  312. package/src/rules/no-unsafe-dynamic-require/index.js +0 -106
  313. package/src/rules/no-unsafe-regex-construction/index.d.ts +0 -9
  314. package/src/rules/no-unsafe-regex-construction/index.js +0 -291
  315. package/src/rules/no-unsanitized-html/index.d.ts +0 -9
  316. package/src/rules/no-unsanitized-html/index.js +0 -335
  317. package/src/rules/no-unvalidated-deeplinks/index.d.ts +0 -6
  318. package/src/rules/no-unvalidated-deeplinks/index.js +0 -62
  319. package/src/rules/no-unvalidated-user-input/index.d.ts +0 -9
  320. package/src/rules/no-unvalidated-user-input/index.js +0 -420
  321. package/src/rules/no-verbose-error-messages/index.d.ts +0 -8
  322. package/src/rules/no-verbose-error-messages/index.js +0 -68
  323. package/src/rules/no-weak-crypto/index.d.ts +0 -11
  324. package/src/rules/no-weak-crypto/index.js +0 -351
  325. package/src/rules/no-weak-password-recovery/index.d.ts +0 -12
  326. package/src/rules/no-weak-password-recovery/index.js +0 -424
  327. package/src/rules/no-xpath-injection/index.d.ts +0 -10
  328. package/src/rules/no-xpath-injection/index.js +0 -487
  329. package/src/rules/no-xxe-injection/index.d.ts +0 -7
  330. package/src/rules/no-xxe-injection/index.js +0 -266
  331. package/src/rules/no-zip-slip/index.d.ts +0 -9
  332. package/src/rules/no-zip-slip/index.js +0 -445
  333. package/src/rules/require-backend-authorization/index.d.ts +0 -6
  334. package/src/rules/require-backend-authorization/index.js +0 -60
  335. package/src/rules/require-code-minification/index.d.ts +0 -8
  336. package/src/rules/require-code-minification/index.js +0 -47
  337. package/src/rules/require-csp-headers/index.d.ts +0 -6
  338. package/src/rules/require-csp-headers/index.js +0 -64
  339. package/src/rules/require-data-minimization/index.d.ts +0 -8
  340. package/src/rules/require-data-minimization/index.js +0 -53
  341. package/src/rules/require-dependency-integrity/index.d.ts +0 -6
  342. package/src/rules/require-dependency-integrity/index.js +0 -64
  343. package/src/rules/require-https-only/index.d.ts +0 -8
  344. package/src/rules/require-https-only/index.js +0 -62
  345. package/src/rules/require-mime-type-validation/index.d.ts +0 -6
  346. package/src/rules/require-mime-type-validation/index.js +0 -66
  347. package/src/rules/require-network-timeout/index.d.ts +0 -8
  348. package/src/rules/require-network-timeout/index.js +0 -50
  349. package/src/rules/require-package-lock/index.d.ts +0 -8
  350. package/src/rules/require-package-lock/index.js +0 -63
  351. package/src/rules/require-secure-credential-storage/index.d.ts +0 -8
  352. package/src/rules/require-secure-credential-storage/index.js +0 -50
  353. package/src/rules/require-secure-defaults/index.d.ts +0 -8
  354. package/src/rules/require-secure-defaults/index.js +0 -47
  355. package/src/rules/require-secure-deletion/index.d.ts +0 -8
  356. package/src/rules/require-secure-deletion/index.js +0 -44
  357. package/src/rules/require-storage-encryption/index.d.ts +0 -8
  358. package/src/rules/require-storage-encryption/index.js +0 -50
  359. package/src/rules/require-url-validation/index.d.ts +0 -6
  360. package/src/rules/require-url-validation/index.js +0 -72
  361. package/src/types/index.js +0 -17
@@ -0,0 +1,294 @@
1
+ /**
2
+ * ESLint Rule: no-sensitive-data-exposure
3
+ * Detects PII/credentials in logs, responses, or error messages
4
+ * Priority 5: Security with Data Flow Analysis
5
+ * CWE-532: Information Exposure Through Log Files
6
+ *
7
+ * @see https://cwe.mitre.org/data/definitions/532.html
8
+ */
9
+ import type { TSESLint, TSESTree } from '@interlace/eslint-devkit';
10
+ import { formatLLMMessage, MessageIcons } from '@interlace/eslint-devkit';
11
+ import { createRule } from '@interlace/eslint-devkit';
12
+
13
+ type MessageIds =
14
+ | 'sensitiveDataExposure'
15
+ | 'redactData'
16
+ | 'useMasking'
17
+ | 'removeFromLogs';
18
+
19
+ export interface Options {
20
+ /** Sensitive data patterns. Default: ['password', 'secret', 'token', 'key', 'ssn', 'credit', 'card'] */
21
+ sensitivePatterns?: string[];
22
+
23
+ /** Check console.log statements. Default: true */
24
+ checkConsoleLog?: boolean;
25
+
26
+ /** Check error messages. Default: true */
27
+ checkErrorMessages?: boolean;
28
+
29
+ /** Check API responses. Default: true */
30
+ checkApiResponses?: boolean;
31
+ }
32
+
33
+ type RuleOptions = [Options?];
34
+
35
+ /**
36
+ * Check if string contains sensitive data patterns
37
+ */
38
+ function containsSensitiveData(
39
+ text: string,
40
+ patterns: string[]
41
+ ): boolean {
42
+ const lowerText = text.toLowerCase();
43
+ return patterns.some(pattern => lowerText.includes(pattern.toLowerCase()));
44
+ }
45
+
46
+
47
+ export const noSensitiveDataExposure = createRule<RuleOptions, MessageIds>({
48
+ name: 'no-sensitive-data-exposure',
49
+ meta: {
50
+ type: 'problem',
51
+ docs: {
52
+ description: 'Detects PII/credentials in logs, responses, or error messages',
53
+ },
54
+ hasSuggestions: true,
55
+ messages: {
56
+ sensitiveDataExposure: formatLLMMessage({
57
+ icon: MessageIcons.SECURITY,
58
+ issueName: 'Sensitive data exposure',
59
+ cwe: 'CWE-532',
60
+ description: 'Sensitive data detected in {{context}}: {{dataType}}',
61
+ severity: 'HIGH',
62
+ fix: 'Redact or mask sensitive data before logging/exposing',
63
+ documentationLink: 'https://cwe.mitre.org/data/definitions/532.html',
64
+ }),
65
+ redactData: formatLLMMessage({
66
+ icon: MessageIcons.INFO,
67
+ issueName: 'Redact Data',
68
+ description: 'Redact sensitive data before logging',
69
+ severity: 'LOW',
70
+ fix: 'Redact sensitive fields before logging',
71
+ documentationLink: 'https://cwe.mitre.org/data/definitions/532.html',
72
+ }),
73
+ useMasking: formatLLMMessage({
74
+ icon: MessageIcons.INFO,
75
+ issueName: 'Use Masking',
76
+ description: 'Use data masking function',
77
+ severity: 'LOW',
78
+ fix: 'maskSensitive(data)',
79
+ documentationLink: 'https://cwe.mitre.org/data/definitions/532.html',
80
+ }),
81
+ removeFromLogs: formatLLMMessage({
82
+ icon: MessageIcons.INFO,
83
+ issueName: 'Remove From Logs',
84
+ description: 'Remove sensitive data from logs and errors',
85
+ severity: 'LOW',
86
+ fix: 'Filter sensitive data before logging',
87
+ documentationLink: 'https://cwe.mitre.org/data/definitions/532.html',
88
+ }),
89
+ },
90
+ schema: [
91
+ {
92
+ type: 'object',
93
+ properties: {
94
+ sensitivePatterns: {
95
+ type: 'array',
96
+ items: { type: 'string' },
97
+ default: ['password', 'secret', 'token', 'key', 'ssn', 'credit', 'card', 'api_key', 'apikey'],
98
+ description: 'Sensitive data patterns',
99
+ },
100
+ checkConsoleLog: {
101
+ type: 'boolean',
102
+ default: true,
103
+ description: 'Check console.log statements',
104
+ },
105
+ checkErrorMessages: {
106
+ type: 'boolean',
107
+ default: true,
108
+ description: 'Check error messages',
109
+ },
110
+ checkApiResponses: {
111
+ type: 'boolean',
112
+ default: true,
113
+ description: 'Check API responses',
114
+ },
115
+ },
116
+ additionalProperties: false,
117
+ },
118
+ ],
119
+ },
120
+ defaultOptions: [
121
+ {
122
+ sensitivePatterns: ['password', 'secret', 'token', 'key', 'ssn', 'credit', 'card', 'api_key', 'apikey'],
123
+ checkConsoleLog: true,
124
+ checkErrorMessages: true,
125
+ checkApiResponses: true,
126
+ },
127
+ ],
128
+ create(context: TSESLint.RuleContext<MessageIds, RuleOptions>, [options = {}]) {
129
+ const {
130
+ sensitivePatterns = ['password', 'secret', 'token', 'key', 'ssn', 'credit', 'card', 'api_key', 'apikey'],
131
+ checkConsoleLog = true,
132
+ checkErrorMessages = true,
133
+
134
+ }: Options = options || {};
135
+
136
+ /**
137
+ * Check CallExpression for logging calls with sensitive data
138
+ */
139
+ function checkCallExpression(node: TSESTree.CallExpression) {
140
+ // Check if it's a logging call (console.*, logger.*)
141
+ const isLoggingCall = (() => {
142
+ if (node.callee.type === 'MemberExpression') {
143
+ const object = node.callee.object;
144
+ const property = node.callee.property;
145
+ if (property.type === 'Identifier') {
146
+ const methodName = property.name.toLowerCase();
147
+ if (['log', 'info', 'warn', 'error', 'debug', 'trace'].includes(methodName)) {
148
+ // Check if it's console.* or logger.*
149
+ if (object.type === 'Identifier') {
150
+ const objName = object.name.toLowerCase();
151
+ if (objName === 'console' || objName === 'logger') {
152
+ return true;
153
+ }
154
+ }
155
+ }
156
+ }
157
+ } else if (node.callee.type === 'Identifier') {
158
+ // Check for logger.info() pattern
159
+ const calleeName = node.callee.name.toLowerCase();
160
+ if (calleeName.includes('log') || calleeName.includes('logger')) {
161
+ return true;
162
+ }
163
+ }
164
+ return false;
165
+ })();
166
+
167
+ if (isLoggingCall && checkConsoleLog) {
168
+
169
+ // Check if any argument contains sensitive data
170
+ for (const arg of node.arguments) {
171
+ if (arg.type === 'Literal' && typeof arg.value === 'string') {
172
+ const text = arg.value;
173
+ if (containsSensitiveData(text, sensitivePatterns)) {
174
+ context.report({
175
+ node: arg,
176
+ messageId: 'sensitiveDataExposure',
177
+ data: {
178
+ context: 'logs',
179
+ dataType: 'password',
180
+ },
181
+ suggest: [
182
+ { messageId: 'redactData', fix: () => null },
183
+ { messageId: 'useMasking', fix: () => null },
184
+ { messageId: 'removeFromLogs', fix: () => null },
185
+ ],
186
+ });
187
+ return; // Only report once per call
188
+ }
189
+ } else if (arg.type === 'Identifier' && arg.name) {
190
+ const name = arg.name.toLowerCase();
191
+ if (containsSensitiveData(name, sensitivePatterns)) {
192
+ context.report({
193
+ node: arg,
194
+ messageId: 'sensitiveDataExposure',
195
+ data: {
196
+ context: 'logs',
197
+ dataType: 'password',
198
+ },
199
+ suggest: [
200
+ { messageId: 'redactData', fix: () => null },
201
+ { messageId: 'useMasking', fix: () => null },
202
+ { messageId: 'removeFromLogs', fix: () => null },
203
+ ],
204
+ });
205
+ return; // Only report once per call
206
+ }
207
+ }
208
+ }
209
+ }
210
+ }
211
+
212
+ /**
213
+ * Check NewExpression for Error with sensitive data
214
+ */
215
+ function checkNewExpression(node: TSESTree.NewExpression) {
216
+ if (!checkErrorMessages) {
217
+ return;
218
+ }
219
+
220
+ if (node.callee && node.callee.type === 'Identifier' && node.callee.name === 'Error') {
221
+ // Check all arguments for sensitive data (report only once per error)
222
+ for (const arg of node.arguments) {
223
+ if (arg.type === 'Literal' && typeof arg.value === 'string') {
224
+ const text = arg.value;
225
+ if (containsSensitiveData(text, sensitivePatterns)) {
226
+ context.report({
227
+ node: arg,
228
+ messageId: 'sensitiveDataExposure',
229
+ data: {
230
+ context: 'error messages',
231
+ dataType: 'password',
232
+ },
233
+ suggest: [
234
+ { messageId: 'redactData', fix: () => null },
235
+ { messageId: 'useMasking', fix: () => null },
236
+ { messageId: 'removeFromLogs', fix: () => null },
237
+ ],
238
+ });
239
+ return; // Only report once per error
240
+ }
241
+ } else if (arg.type === 'BinaryExpression' && arg.operator === '+') {
242
+ // Check left side if it's a literal
243
+ if (arg.left && arg.left.type === 'Literal' && typeof arg.left.value === 'string') {
244
+ const leftText = arg.left.value;
245
+ if (containsSensitiveData(leftText, sensitivePatterns)) {
246
+ context.report({
247
+ node: arg.left,
248
+ messageId: 'sensitiveDataExposure',
249
+ data: {
250
+ context: 'error messages',
251
+ dataType: 'password',
252
+ },
253
+ suggest: [
254
+ { messageId: 'redactData', fix: () => null },
255
+ { messageId: 'useMasking', fix: () => null },
256
+ { messageId: 'removeFromLogs', fix: () => null },
257
+ ],
258
+ });
259
+ return; // Only report once per error
260
+ }
261
+ }
262
+ // Check right side if it's an identifier
263
+ if (arg.right && arg.right.type === 'Identifier' && arg.right.name) {
264
+ const rightName = arg.right.name.toLowerCase();
265
+ if (containsSensitiveData(rightName, sensitivePatterns)) {
266
+ context.report({
267
+ node: arg.right,
268
+ messageId: 'sensitiveDataExposure',
269
+ data: {
270
+ context: 'error messages',
271
+ dataType: 'password',
272
+ },
273
+ suggest: [
274
+ { messageId: 'redactData', fix: () => null },
275
+ { messageId: 'useMasking', fix: () => null },
276
+ { messageId: 'removeFromLogs', fix: () => null },
277
+ ],
278
+ });
279
+ return; // Only report once per error
280
+ }
281
+ }
282
+ }
283
+ }
284
+ }
285
+ }
286
+
287
+ return {
288
+ CallExpression: checkCallExpression,
289
+ NewExpression: checkNewExpression,
290
+ };
291
+ },
292
+ });
293
+
294
+
@@ -0,0 +1,262 @@
1
+ /**
2
+ * Comprehensive tests for no-sensitive-data-exposure rule
3
+ * Security: Detects PII/credentials in logs, responses, or error messages
4
+ */
5
+ import { RuleTester } from '@typescript-eslint/rule-tester';
6
+ import { describe, it, afterAll } from 'vitest';
7
+ import parser from '@typescript-eslint/parser';
8
+ import { noSensitiveDataExposure } from './index';
9
+
10
+ RuleTester.afterAll = afterAll;
11
+ RuleTester.it = it;
12
+ RuleTester.itOnly = it.only;
13
+ RuleTester.describe = describe;
14
+
15
+ const ruleTester = new RuleTester({
16
+ languageOptions: {
17
+ parser,
18
+ ecmaVersion: 2022,
19
+ sourceType: 'module',
20
+ },
21
+ });
22
+
23
+ describe('no-sensitive-data-exposure', () => {
24
+ describe('Valid Code', () => {
25
+ ruleTester.run('valid - no sensitive data', noSensitiveDataExposure, {
26
+ valid: [
27
+ // Regular log messages
28
+ {
29
+ code: `console.log('User logged in');`,
30
+ },
31
+ {
32
+ code: `console.log('Hello world');`,
33
+ },
34
+ // Logger methods without sensitive data
35
+ {
36
+ code: `logger.info('Request received');`,
37
+ },
38
+ {
39
+ code: `logger.error('Operation failed');`,
40
+ },
41
+ {
42
+ code: `logger.debug('Processing started');`,
43
+ },
44
+ // Errors without sensitive data
45
+ {
46
+ code: `throw new Error('Operation failed');`,
47
+ },
48
+ {
49
+ code: `new Error('Invalid input');`,
50
+ },
51
+ // Variables with sensitive names not in logs
52
+ {
53
+ code: `const password = process.env.PASSWORD;`,
54
+ },
55
+ // Non-logging function calls with sensitive data (not flagged)
56
+ {
57
+ code: `processData('password value');`,
58
+ },
59
+ {
60
+ code: `fetch('https://api.example.com?token=abc');`,
61
+ },
62
+ // Member expression that's not console/logger
63
+ {
64
+ code: `validator.check('password field');`,
65
+ },
66
+ // Custom patterns - not matching
67
+ {
68
+ code: `console.log('Password:', password);`,
69
+ options: [{ sensitivePatterns: ['secret'] }],
70
+ },
71
+ // Disabled checks
72
+ {
73
+ code: `console.log('password is:', pwd);`,
74
+ options: [{ checkConsoleLog: false }],
75
+ },
76
+ {
77
+ code: `throw new Error('password error');`,
78
+ options: [{ checkErrorMessages: false }],
79
+ },
80
+ ],
81
+ invalid: [],
82
+ });
83
+ });
84
+
85
+ describe('Invalid Code - Console Log', () => {
86
+ ruleTester.run('invalid - console.log with sensitive data', noSensitiveDataExposure, {
87
+ valid: [],
88
+ invalid: [
89
+ // String literal with password
90
+ {
91
+ code: `console.log('password: 123456');`,
92
+ errors: [{ messageId: 'sensitiveDataExposure' }],
93
+ },
94
+ // String literal with token
95
+ {
96
+ code: `console.log('API token: abc123');`,
97
+ errors: [{ messageId: 'sensitiveDataExposure' }],
98
+ },
99
+ // String literal with key
100
+ {
101
+ code: `console.log('secret key value');`,
102
+ errors: [{ messageId: 'sensitiveDataExposure' }],
103
+ },
104
+ // String literal with SSN
105
+ {
106
+ code: `console.log('SSN: 123-45-6789');`,
107
+ errors: [{ messageId: 'sensitiveDataExposure' }],
108
+ },
109
+ // String literal with credit
110
+ {
111
+ code: `console.log('credit card number');`,
112
+ errors: [{ messageId: 'sensitiveDataExposure' }],
113
+ },
114
+ // Identifier with password in name
115
+ {
116
+ code: `console.log(userPassword);`,
117
+ errors: [{ messageId: 'sensitiveDataExposure' }],
118
+ },
119
+ // Identifier with token in name
120
+ {
121
+ code: `console.log(apiToken);`,
122
+ errors: [{ messageId: 'sensitiveDataExposure' }],
123
+ },
124
+ // Identifier with key in name
125
+ {
126
+ code: `console.log(secretKey);`,
127
+ errors: [{ messageId: 'sensitiveDataExposure' }],
128
+ },
129
+ ],
130
+ });
131
+ });
132
+
133
+ describe('Invalid Code - Logger Methods', () => {
134
+ ruleTester.run('invalid - logger with sensitive data', noSensitiveDataExposure, {
135
+ valid: [],
136
+ invalid: [
137
+ // logger.info
138
+ {
139
+ code: `logger.info('password exposed');`,
140
+ errors: [{ messageId: 'sensitiveDataExposure' }],
141
+ },
142
+ // logger.warn
143
+ {
144
+ code: `logger.warn('api_key: xyz');`,
145
+ errors: [{ messageId: 'sensitiveDataExposure' }],
146
+ },
147
+ // logger.error
148
+ {
149
+ code: `logger.error('token invalid');`,
150
+ errors: [{ messageId: 'sensitiveDataExposure' }],
151
+ },
152
+ // logger.debug with identifier
153
+ {
154
+ code: `logger.debug(password);`,
155
+ errors: [{ messageId: 'sensitiveDataExposure' }],
156
+ },
157
+ // console.warn
158
+ {
159
+ code: `console.warn('secret exposed');`,
160
+ errors: [{ messageId: 'sensitiveDataExposure' }],
161
+ },
162
+ // console.error
163
+ {
164
+ code: `console.error('apikey error');`,
165
+ errors: [{ messageId: 'sensitiveDataExposure' }],
166
+ },
167
+ // console.debug
168
+ {
169
+ code: `console.debug(apiKey);`,
170
+ errors: [{ messageId: 'sensitiveDataExposure' }],
171
+ },
172
+ // console.trace
173
+ {
174
+ code: `console.trace('token trace');`,
175
+ errors: [{ messageId: 'sensitiveDataExposure' }],
176
+ },
177
+ ],
178
+ });
179
+ });
180
+
181
+ describe('Invalid Code - Identifier-based Logging', () => {
182
+ ruleTester.run('invalid - log() function with sensitive data', noSensitiveDataExposure, {
183
+ valid: [],
184
+ invalid: [
185
+ // Direct log() function call
186
+ {
187
+ code: `log('password: 123');`,
188
+ errors: [{ messageId: 'sensitiveDataExposure' }],
189
+ },
190
+ // customLogger() function
191
+ {
192
+ code: `customLogger('token exposed');`,
193
+ errors: [{ messageId: 'sensitiveDataExposure' }],
194
+ },
195
+ ],
196
+ });
197
+ });
198
+
199
+ describe('Invalid Code - Error Messages', () => {
200
+ ruleTester.run('invalid - Error with sensitive data', noSensitiveDataExposure, {
201
+ valid: [],
202
+ invalid: [
203
+ // String literal with password
204
+ {
205
+ code: `throw new Error('password is invalid');`,
206
+ errors: [{ messageId: 'sensitiveDataExposure' }],
207
+ },
208
+ // String literal with token
209
+ {
210
+ code: `new Error('token expired');`,
211
+ errors: [{ messageId: 'sensitiveDataExposure' }],
212
+ },
213
+ // String literal with secret
214
+ {
215
+ code: `throw new Error('secret not found');`,
216
+ errors: [{ messageId: 'sensitiveDataExposure' }],
217
+ },
218
+ // BinaryExpression with sensitive left side
219
+ {
220
+ code: `throw new Error('password: ' + value);`,
221
+ errors: [{ messageId: 'sensitiveDataExposure' }],
222
+ },
223
+ // BinaryExpression with sensitive right identifier
224
+ {
225
+ code: `throw new Error('Error: ' + userPassword);`,
226
+ errors: [{ messageId: 'sensitiveDataExposure' }],
227
+ },
228
+ // BinaryExpression with token identifier
229
+ {
230
+ code: `throw new Error('Invalid ' + apiToken);`,
231
+ errors: [{ messageId: 'sensitiveDataExposure' }],
232
+ },
233
+ // BinaryExpression with key identifier
234
+ {
235
+ code: `throw new Error('Missing ' + secretKey);`,
236
+ errors: [{ messageId: 'sensitiveDataExposure' }],
237
+ },
238
+ ],
239
+ });
240
+ });
241
+
242
+ describe('Options - Custom Patterns', () => {
243
+ ruleTester.run('options - custom sensitive patterns', noSensitiveDataExposure, {
244
+ valid: [],
245
+ invalid: [
246
+ // Custom pattern: email
247
+ {
248
+ code: `console.log('user email: test@example.com');`,
249
+ options: [{ sensitivePatterns: ['email'] }],
250
+ errors: [{ messageId: 'sensitiveDataExposure' }],
251
+ },
252
+ // Custom pattern: phone
253
+ {
254
+ code: `logger.info('phone number logged');`,
255
+ options: [{ sensitivePatterns: ['phone'] }],
256
+ errors: [{ messageId: 'sensitiveDataExposure' }],
257
+ },
258
+ ],
259
+ });
260
+ });
261
+ });
262
+
@@ -0,0 +1,73 @@
1
+ /**
2
+ * @fileoverview Prevent PII sent to analytics
3
+ * @see https://owasp.org/www-project-mobile-top-10/
4
+ * @see https://cwe.mitre.org/data/definitions/359.html
5
+ */
6
+
7
+ import { createRule, formatLLMMessage, MessageIcons } from '@interlace/eslint-devkit';
8
+ import type { TSESTree } from '@interlace/eslint-devkit';
9
+
10
+ type MessageIds = 'violationDetected';
11
+
12
+ // eslint-disable-next-line @typescript-eslint/no-empty-object-type, @typescript-eslint/no-empty-interface -- Rule has no configurable options
13
+ export interface Options {}
14
+
15
+ type RuleOptions = [Options?];
16
+
17
+ export const noSensitiveDataInAnalytics = createRule<RuleOptions, MessageIds>({
18
+ name: 'no-sensitive-data-in-analytics',
19
+ meta: {
20
+ type: 'problem',
21
+ docs: {
22
+ description: 'Prevent PII being sent to analytics services',
23
+ category: 'Security',
24
+ recommended: true,
25
+ owaspMobile: ['M6'],
26
+ cweIds: ['CWE-359'],
27
+ },
28
+ messages: {
29
+ violationDetected: formatLLMMessage({
30
+ icon: MessageIcons.SECURITY,
31
+ issueName: 'Sensitive Data in Analytics',
32
+ cwe: 'CWE-359',
33
+ description: 'Sensitive field sent to analytics - this is a privacy violation',
34
+ severity: 'HIGH',
35
+ fix: 'Remove PII from analytics tracking data',
36
+ documentationLink: 'https://cwe.mitre.org/data/definitions/359.html',
37
+ })
38
+ },
39
+ schema: [],
40
+ },
41
+ defaultOptions: [],
42
+ create(context) {
43
+ const sensitiveFields = ['email', 'ssn', 'creditcard', 'password', 'phone', 'address'];
44
+
45
+ function report(node: TSESTree.Node, field: string) {
46
+ context.report({ node, messageId: 'violationDetected', data: { field } });
47
+ }
48
+
49
+ return {
50
+ CallExpression(node: TSESTree.CallExpression) {
51
+ // analytics.track() with sensitive data
52
+ if (node.callee.type === 'MemberExpression' &&
53
+ node.callee.object.name === 'analytics' &&
54
+ node.callee.property.name === 'track') {
55
+
56
+ const dataArg = node.arguments[1];
57
+ if (dataArg?.type === 'ObjectExpression') {
58
+ dataArg.properties.forEach(prop => {
59
+ if (prop.type === 'Property') {
60
+ const key = prop.key.name?.toLowerCase();
61
+ const matchedField = sensitiveFields.find(f => key?.includes(f));
62
+ if (matchedField) {
63
+ report(prop, matchedField);
64
+ }
65
+ }
66
+ });
67
+ }
68
+ }
69
+ },
70
+ };
71
+ },
72
+ });
73
+
@@ -0,0 +1,42 @@
1
+ /**
2
+ * @fileoverview Tests for no-sensitive-data-in-analytics
3
+ */
4
+
5
+ import { RuleTester } from '@typescript-eslint/rule-tester';
6
+ import { noSensitiveDataInAnalytics } from './index';
7
+
8
+ const ruleTester = new RuleTester({
9
+ languageOptions: {
10
+ ecmaVersion: 2022,
11
+ sourceType: 'module',
12
+ },
13
+ });
14
+
15
+ ruleTester.run('no-sensitive-data-in-analytics', noSensitiveDataInAnalytics, {
16
+ valid: [
17
+ // Non-sensitive analytics
18
+ { code: "analytics.track('page_view', { page: '/home' })" },
19
+ { code: "analytics.track('click', { element: 'button', action: 'submit' })" },
20
+ { code: "gtag('event', 'click', { element: 'button' })" },
21
+ // Non-analytics code
22
+ { code: "const x = 1" },
23
+ ],
24
+
25
+ invalid: [
26
+ // Email in analytics
27
+ { code: "analytics.track('signup', { email: user.email })", errors: [{ messageId: 'violationDetected' }] },
28
+ { code: "analytics.track('login', { userEmail: email })", errors: [{ messageId: 'violationDetected' }] },
29
+ // SSN
30
+ { code: "analytics.track('verify', { ssn: userSSN })", errors: [{ messageId: 'violationDetected' }] },
31
+ // Credit card
32
+ { code: "analytics.track('purchase', { creditcard: card })", errors: [{ messageId: 'violationDetected' }] },
33
+ // Password
34
+ { code: "analytics.track('auth', { password: pwd })", errors: [{ messageId: 'violationDetected' }] },
35
+ // Phone
36
+ { code: "analytics.track('contact', { phone: number })", errors: [{ messageId: 'violationDetected' }] },
37
+ // Address
38
+ { code: "analytics.track('order', { address: addr })", errors: [{ messageId: 'violationDetected' }] },
39
+ // Multiple sensitive fields
40
+ { code: "analytics.track('profile', { email: e, phone: p })", errors: [{ messageId: 'violationDetected' }, { messageId: 'violationDetected' }] },
41
+ ],
42
+ });