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,596 @@
1
+ /**
2
+ * ESLint Rule: no-xpath-injection
3
+ * Detects XPath injection vulnerabilities (CWE-643)
4
+ *
5
+ * XPath injection occurs when user input is improperly inserted into XPath
6
+ * queries, allowing attackers to:
7
+ * - Access unauthorized XML nodes and data
8
+ * - Extract sensitive information from XML documents
9
+ * - Perform XPath-based attacks and data exfiltration
10
+ * - Bypass authentication or authorization checks
11
+ *
12
+ * False Positive Reduction:
13
+ * This rule uses security utilities to reduce false positives by detecting:
14
+ * - Safe XPath construction methods
15
+ * - Input validation and sanitization
16
+ * - JSDoc annotations (@xpath-safe, @validated)
17
+ * - Trusted XPath libraries
18
+ */
19
+ import type { TSESLint, TSESTree } from '@interlace/eslint-devkit';
20
+ import { createRule } from '@interlace/eslint-devkit';
21
+ import { formatLLMMessage, MessageIcons } from '@interlace/eslint-devkit';
22
+ import {
23
+ createSafetyChecker,
24
+ hasSafeAnnotation,
25
+ type SecurityRuleOptions,
26
+ } from '@interlace/eslint-devkit';
27
+
28
+ type MessageIds =
29
+ | 'xpathInjection'
30
+ | 'unsafeXpathConcatenation'
31
+ | 'unvalidatedXpathInput'
32
+ | 'dangerousXpathExpression'
33
+ | 'useParameterizedXpath'
34
+ | 'escapeXpathInput'
35
+ | 'validateXpathQueries'
36
+ | 'strategyParameterizedQueries'
37
+ | 'strategyInputValidation'
38
+ | 'strategySafeConstruction';
39
+
40
+ export interface Options extends SecurityRuleOptions {
41
+ /** XPath-related function names to check */
42
+ xpathFunctions?: string[];
43
+
44
+ /** Functions that safely construct XPath queries */
45
+ safeXpathConstructors?: string[];
46
+
47
+ /** Functions that validate/sanitize XPath input */
48
+ xpathValidationFunctions?: string[];
49
+ }
50
+
51
+ type RuleOptions = [Options?];
52
+
53
+ export const noXpathInjection = createRule<RuleOptions, MessageIds>({
54
+ name: 'no-xpath-injection',
55
+ meta: {
56
+ type: 'problem',
57
+ docs: {
58
+ description: 'Detects XPath injection vulnerabilities',
59
+ },
60
+ fixable: 'code',
61
+ hasSuggestions: true,
62
+ messages: {
63
+ xpathInjection: formatLLMMessage({
64
+ icon: MessageIcons.SECURITY,
65
+ issueName: 'XPath Injection',
66
+ cwe: 'CWE-643',
67
+ description: 'XPath injection vulnerability detected',
68
+ severity: '{{severity}}',
69
+ fix: '{{safeAlternative}}',
70
+ documentationLink: 'https://cwe.mitre.org/data/definitions/643.html',
71
+ }),
72
+ unsafeXpathConcatenation: formatLLMMessage({
73
+ icon: MessageIcons.SECURITY,
74
+ issueName: 'Unsafe XPath Concatenation',
75
+ cwe: 'CWE-643',
76
+ description: 'Unsafe string concatenation in XPath expression',
77
+ severity: 'HIGH',
78
+ fix: 'Use parameterized XPath or escape user input',
79
+ documentationLink: 'https://owasp.org/www-community/attacks/XPATH_Injection',
80
+ }),
81
+ unvalidatedXpathInput: formatLLMMessage({
82
+ icon: MessageIcons.SECURITY,
83
+ issueName: 'Unvalidated XPath Input',
84
+ cwe: 'CWE-643',
85
+ description: 'XPath query uses unvalidated user input',
86
+ severity: 'MEDIUM',
87
+ fix: 'Validate and sanitize XPath input before use',
88
+ documentationLink: 'https://owasp.org/www-community/attacks/XPATH_Injection',
89
+ }),
90
+ dangerousXpathExpression: formatLLMMessage({
91
+ icon: MessageIcons.SECURITY,
92
+ issueName: 'Dangerous XPath Expression',
93
+ cwe: 'CWE-643',
94
+ description: 'XPath expression allows dangerous operations',
95
+ severity: 'MEDIUM',
96
+ fix: 'Restrict XPath to safe patterns and validate expressions',
97
+ documentationLink: 'https://cwe.mitre.org/data/definitions/643.html',
98
+ }),
99
+ useParameterizedXpath: formatLLMMessage({
100
+ icon: MessageIcons.INFO,
101
+ issueName: 'Use Parameterized XPath',
102
+ description: 'Use parameterized XPath queries',
103
+ severity: 'LOW',
104
+ fix: 'Construct XPath with proper escaping and validation',
105
+ documentationLink: 'https://owasp.org/www-community/attacks/XPATH_Injection',
106
+ }),
107
+ escapeXpathInput: formatLLMMessage({
108
+ icon: MessageIcons.INFO,
109
+ issueName: 'Escape XPath Input',
110
+ description: 'Escape special characters in XPath input',
111
+ severity: 'LOW',
112
+ fix: 'Use xpath.escape() or equivalent escaping function',
113
+ documentationLink: 'https://www.npmjs.com/package/xpath-escape',
114
+ }),
115
+ validateXpathQueries: formatLLMMessage({
116
+ icon: MessageIcons.INFO,
117
+ issueName: 'Validate XPath Queries',
118
+ description: 'Validate XPath queries against allowed patterns',
119
+ severity: 'LOW',
120
+ fix: 'Whitelist allowed XPath operations and validate syntax',
121
+ documentationLink: 'https://owasp.org/www-community/attacks/XPATH_Injection',
122
+ }),
123
+ strategyParameterizedQueries: formatLLMMessage({
124
+ icon: MessageIcons.STRATEGY,
125
+ issueName: 'Parameterized Queries Strategy',
126
+ description: 'Use parameterized XPath construction',
127
+ severity: 'LOW',
128
+ fix: 'Build XPath queries programmatically with escaped parameters',
129
+ documentationLink: 'https://owasp.org/www-community/attacks/XPATH_Injection',
130
+ }),
131
+ strategyInputValidation: formatLLMMessage({
132
+ icon: MessageIcons.STRATEGY,
133
+ issueName: 'Input Validation Strategy',
134
+ description: 'Validate XPath input at application boundary',
135
+ severity: 'LOW',
136
+ fix: 'Validate XPath syntax and restrict to safe operations',
137
+ documentationLink: 'https://cwe.mitre.org/data/definitions/643.html',
138
+ }),
139
+ strategySafeConstruction: formatLLMMessage({
140
+ icon: MessageIcons.STRATEGY,
141
+ issueName: 'Safe Construction Strategy',
142
+ description: 'Use safe XPath construction libraries',
143
+ severity: 'LOW',
144
+ fix: 'Use libraries that provide safe XPath building',
145
+ documentationLink: 'https://www.npmjs.com/package/xpath-builder',
146
+ })
147
+ },
148
+ schema: [
149
+ {
150
+ type: 'object',
151
+ properties: {
152
+ xpathFunctions: {
153
+ type: 'array',
154
+ items: { type: 'string' },
155
+ default: ['evaluate', 'selectSingleNode', 'selectNodes', 'xpath', 'select'],
156
+ },
157
+ safeXpathConstructors: {
158
+ type: 'array',
159
+ items: { type: 'string' },
160
+ default: ['buildXPath', 'createXPath', 'safeXPath', 'xpathBuilder'],
161
+ },
162
+ xpathValidationFunctions: {
163
+ type: 'array',
164
+ items: { type: 'string' },
165
+ default: ['validateXPath', 'escapeXPath', 'sanitizeXPath', 'cleanXPath'],
166
+ },
167
+ trustedSanitizers: {
168
+ type: 'array',
169
+ items: { type: 'string' },
170
+ default: [],
171
+ description: 'Additional function names to consider as XPath sanitizers',
172
+ },
173
+ trustedAnnotations: {
174
+ type: 'array',
175
+ items: { type: 'string' },
176
+ default: [],
177
+ description: 'Additional JSDoc annotations to consider as safe markers',
178
+ },
179
+ strictMode: {
180
+ type: 'boolean',
181
+ default: false,
182
+ description: 'Disable all false positive detection (strict mode)',
183
+ },
184
+ },
185
+ additionalProperties: false,
186
+ },
187
+ ],
188
+ },
189
+ defaultOptions: [
190
+ {
191
+ xpathFunctions: ['evaluate', 'selectSingleNode', 'selectNodes', 'xpath', 'select'],
192
+ safeXpathConstructors: ['buildXPath', 'createXPath', 'safeXPath', 'xpathBuilder'],
193
+ xpathValidationFunctions: ['validateXPath', 'escapeXPath', 'sanitizeXPath', 'cleanXPath'],
194
+ trustedSanitizers: [],
195
+ trustedAnnotations: ['@xpath-safe'],
196
+ strictMode: false,
197
+ },
198
+ ],
199
+ create(context: TSESLint.RuleContext<MessageIds, RuleOptions>) {
200
+ const options = context.options[0] || {};
201
+ const {
202
+ xpathFunctions = ['evaluate', 'selectSingleNode', 'selectNodes', 'xpath', 'select'],
203
+ safeXpathConstructors = ['buildXPath', 'createXPath', 'safeXPath', 'xpathBuilder'],
204
+ xpathValidationFunctions = ['validateXPath', 'escapeXPath', 'sanitizeXPath', 'cleanXPath'],
205
+ trustedSanitizers = [],
206
+ trustedAnnotations = [],
207
+ strictMode = false,
208
+ }: Options = options;
209
+
210
+ const sourceCode = context.sourceCode || context.sourceCode;
211
+ const filename = context.filename || context.getFilename();
212
+
213
+ // Create safety checker for false positive detection
214
+ const safetyChecker = createSafetyChecker({
215
+ trustedSanitizers,
216
+ trustedAnnotations,
217
+ trustedOrmPatterns: [],
218
+ strictMode,
219
+ });
220
+
221
+ // Track variables that have been validated/sanitized
222
+ const validatedVariables = new Set<string>();
223
+
224
+ /**
225
+ * Check if this is an XPath-related operation
226
+ */
227
+ const isXpathOperation = (node: TSESTree.CallExpression): boolean => {
228
+ const callee = node.callee;
229
+
230
+ // Check for XPath method calls
231
+ if (callee.type === 'MemberExpression' &&
232
+ callee.property.type === 'Identifier' &&
233
+ xpathFunctions.includes(callee.property.name)) {
234
+ return true;
235
+ }
236
+
237
+ // Check for XPath library calls
238
+ if (callee.type === 'Identifier' && xpathFunctions.includes(callee.name)) {
239
+ return true;
240
+ }
241
+
242
+ return false;
243
+ };
244
+
245
+ /**
246
+ * Check if XPath expression contains dangerous patterns
247
+ */
248
+ const containsDangerousXpath = (xpathText: string): boolean => {
249
+ // Dangerous XPath patterns that allow traversal or injection
250
+ const dangerousPatterns = [
251
+ /\.\./, // Parent directory traversal
252
+ /\/\*/, // All children selector
253
+ /\[.*\*\]/, // Wildcard in predicates
254
+ /\/\//, // Descendant-or-self axis (can be dangerous in some contexts)
255
+ /text\(\)/, // Content extraction
256
+ /comment\(\)/, // Comment extraction
257
+ /processing-instruction\(\)/, // Processing instruction extraction
258
+ ];
259
+
260
+ return dangerousPatterns.some(pattern => pattern.test(xpathText));
261
+ };
262
+
263
+ /**
264
+ * Check if string contains XPath interpolation
265
+ */
266
+ const containsXpathInterpolation = (text: string): boolean => {
267
+ return /\$\{[^}]+\}/.test(text) || /'[^']*\+[^+]*'/.test(text) || /"[^"]*\+[^+]*"/.test(text);
268
+ };
269
+
270
+ /**
271
+ * Check if XPath input is from untrusted source
272
+ */
273
+ const isUntrustedXpathInput = (inputNode: TSESTree.Node): boolean => {
274
+ if (inputNode.type === 'MemberExpression') {
275
+ // Check patterns like req.query.*, req.body.*, req.params.*
276
+ if (inputNode.object.type === 'MemberExpression' &&
277
+ inputNode.object.object.type === 'Identifier' &&
278
+ inputNode.object.object.name === 'req' &&
279
+ inputNode.object.property.type === 'Identifier' &&
280
+ ['query', 'body', 'params', 'param'].includes(inputNode.object.property.name)) {
281
+ return true;
282
+ }
283
+
284
+ // Check patterns like req.*
285
+ if (inputNode.object.type === 'Identifier' && inputNode.object.name === 'req') {
286
+ return true;
287
+ }
288
+ }
289
+
290
+ if (inputNode.type !== 'Identifier') {
291
+ return false;
292
+ }
293
+
294
+ const varName = inputNode.name.toLowerCase();
295
+ if (['req', 'request', 'query', 'params', 'input', 'user', 'search'].some(keyword =>
296
+ varName.includes(keyword)
297
+ )) {
298
+ return true;
299
+ }
300
+
301
+ // Check if it comes from function parameters
302
+ let current: TSESTree.Node | undefined = inputNode;
303
+ while (current) {
304
+ if (current.type === 'FunctionDeclaration' ||
305
+ current.type === 'FunctionExpression' ||
306
+ current.type === 'ArrowFunctionExpression') {
307
+ const func = current as TSESTree.FunctionDeclaration | TSESTree.FunctionExpression | TSESTree.ArrowFunctionExpression;
308
+ return func.params.some((param: TSESTree.Parameter): boolean => {
309
+ if (param.type === 'Identifier') {
310
+ return param.name === inputNode.name;
311
+ }
312
+ return false;
313
+ });
314
+ }
315
+ current = current.parent as TSESTree.Node;
316
+ }
317
+
318
+ return false;
319
+ };
320
+
321
+ /**
322
+ * Check if XPath input has been validated
323
+ */
324
+ const isXpathInputValidated = (inputNode: TSESTree.Node): boolean => {
325
+ let current: TSESTree.Node | undefined = inputNode;
326
+
327
+ while (current) {
328
+ if (current.type === 'CallExpression' &&
329
+ current.callee.type === 'Identifier' &&
330
+ xpathValidationFunctions.includes(current.callee.name)) {
331
+ return true;
332
+ }
333
+ current = current.parent as TSESTree.Node;
334
+ }
335
+
336
+ return false;
337
+ };
338
+
339
+ /**
340
+ * Check for safe annotation on containing statement or variable declaration
341
+ */
342
+ const hasSafeAnnotationOnStatement = (node: TSESTree.Node): boolean => {
343
+ let current: TSESTree.Node | undefined = node;
344
+
345
+ // Walk up to find VariableDeclaration, ExpressionStatement, FunctionDeclaration, or containing statement
346
+ while (current) {
347
+ if (current.type === 'VariableDeclaration' ||
348
+ current.type === 'ExpressionStatement' ||
349
+ current.type === 'FunctionDeclaration') {
350
+ // Check for JSDoc comments before this statement
351
+ const comments = sourceCode.getCommentsBefore(current);
352
+ for (const comment of comments) {
353
+ if (comment.type === 'Block' && comment.value.includes('@xpath-safe')) {
354
+ return true;
355
+ }
356
+ }
357
+ }
358
+ current = current.parent as TSESTree.Node;
359
+ }
360
+
361
+ return false;
362
+ };
363
+
364
+ /**
365
+ * Check if XPath is constructed safely
366
+ */
367
+ const isSafeXpathConstruction = (node: TSESTree.Node): boolean => {
368
+ let current: TSESTree.Node | undefined = node;
369
+
370
+ while (current) {
371
+ if (current.type === 'CallExpression' &&
372
+ current.callee.type === 'Identifier' &&
373
+ safeXpathConstructors.includes(current.callee.name)) {
374
+ return true;
375
+ }
376
+ current = current.parent as TSESTree.Node;
377
+ }
378
+
379
+ return false;
380
+ };
381
+
382
+ return {
383
+ // Check XPath function calls
384
+ CallExpression(node: TSESTree.CallExpression) {
385
+ if (!isXpathOperation(node)) {
386
+ return;
387
+ }
388
+
389
+ const args = node.arguments;
390
+ if (args.length === 0) {
391
+ return;
392
+ }
393
+
394
+ // Check first argument (usually the XPath expression)
395
+ const xpathArg = args[0];
396
+
397
+ if (xpathArg.type === 'Literal' && typeof xpathArg.value === 'string') {
398
+ const xpathText = xpathArg.value;
399
+
400
+ // Check for dangerous XPath patterns
401
+ if (containsDangerousXpath(xpathText)) {
402
+ // FALSE POSITIVE REDUCTION: Skip if annotated as safe
403
+ if (hasSafeAnnotation(xpathArg, context, trustedAnnotations) || hasSafeAnnotationOnStatement(node)) {
404
+ return;
405
+ }
406
+
407
+ context.report({
408
+ node: xpathArg,
409
+ messageId: 'dangerousXpathExpression',
410
+ data: {
411
+ filePath: filename,
412
+ line: String(node.loc?.start.line ?? 0),
413
+ },
414
+ });
415
+ }
416
+ } else if (xpathArg.type === 'Identifier') {
417
+ // Check if XPath comes from untrusted input
418
+ if (isUntrustedXpathInput(xpathArg) && !isXpathInputValidated(xpathArg) &&
419
+ !(xpathArg.type === 'Identifier' && validatedVariables.has(xpathArg.name))) {
420
+ // FALSE POSITIVE REDUCTION
421
+ if (hasSafeAnnotation(xpathArg, context, trustedAnnotations) || safetyChecker.isSafe(xpathArg, context) || hasSafeAnnotationOnStatement(node)) {
422
+ return;
423
+ }
424
+
425
+ context.report({
426
+ node: xpathArg,
427
+ messageId: 'unvalidatedXpathInput',
428
+ data: {
429
+ filePath: filename,
430
+ line: String(node.loc?.start.line ?? 0),
431
+ },
432
+ });
433
+ }
434
+ }
435
+ },
436
+
437
+ // Check template literals for XPath expressions
438
+ TemplateLiteral(node: TSESTree.TemplateLiteral) {
439
+ const fullText = sourceCode.getText(node);
440
+
441
+ // Check if this looks like an XPath expression
442
+ if (!fullText.includes('/') && !fullText.includes('[') && !fullText.includes('@')) {
443
+ return;
444
+ }
445
+
446
+ // Check for interpolation in XPath-like expressions
447
+ if (containsXpathInterpolation(fullText)) {
448
+ // Check if any interpolated values are untrusted
449
+ const hasUntrustedInterpolation = node.expressions.some((expr: TSESTree.Expression) =>
450
+ isUntrustedXpathInput(expr) && !isXpathInputValidated(expr) && !(expr.type === 'Identifier' && validatedVariables.has(expr.name))
451
+ );
452
+
453
+ if (hasUntrustedInterpolation) {
454
+ // FALSE POSITIVE REDUCTION: Check for safe annotation
455
+ if (hasSafeAnnotationOnStatement(node)) {
456
+ return;
457
+ }
458
+
459
+ context.report({
460
+ node,
461
+ messageId: 'unsafeXpathConcatenation',
462
+ data: {
463
+ filePath: filename,
464
+ line: String(node.loc?.start.line ?? 0),
465
+ },
466
+ suggest: [
467
+ {
468
+ messageId: 'useParameterizedXpath',
469
+ fix: () => null
470
+ },
471
+ ],
472
+ });
473
+ }
474
+ }
475
+
476
+ // Check for dangerous patterns in template literals
477
+ if (containsDangerousXpath(fullText)) {
478
+ // FALSE POSITIVE REDUCTION: Check for safe annotation
479
+ if (hasSafeAnnotationOnStatement(node)) {
480
+ return;
481
+ }
482
+
483
+ context.report({
484
+ node,
485
+ messageId: 'dangerousXpathExpression',
486
+ data: {
487
+ filePath: filename,
488
+ line: String(node.loc?.start.line ?? 0),
489
+ },
490
+ });
491
+ }
492
+ },
493
+
494
+ // Check binary expressions (string concatenation)
495
+ BinaryExpression(node: TSESTree.BinaryExpression) {
496
+ if (node.operator !== '+') {
497
+ return;
498
+ }
499
+
500
+ const fullText = sourceCode.getText(node);
501
+
502
+ // Check if this looks like XPath construction
503
+ if (!fullText.includes('/') && !fullText.includes('[')) {
504
+ return;
505
+ }
506
+
507
+ // Check if either side contains XPath-like patterns
508
+ const leftText = sourceCode.getText(node.left);
509
+ const rightText = sourceCode.getText(node.right);
510
+
511
+ if ((leftText.includes('/') || leftText.includes('[')) ||
512
+ (rightText.includes('/') || rightText.includes('['))) {
513
+
514
+ // Check if untrusted input is involved
515
+ const leftUntrusted = isUntrustedXpathInput(node.left) && !isXpathInputValidated(node.left) && !(node.left.type === 'Identifier' && validatedVariables.has(node.left.name));
516
+ const rightUntrusted = isUntrustedXpathInput(node.right) && !isXpathInputValidated(node.right) && !(node.right.type === 'Identifier' && validatedVariables.has(node.right.name));
517
+
518
+ if (leftUntrusted || rightUntrusted) {
519
+ // FALSE POSITIVE REDUCTION
520
+ if (safetyChecker.isSafe(node, context) || hasSafeAnnotationOnStatement(node)) {
521
+ return;
522
+ }
523
+
524
+ context.report({
525
+ node,
526
+ messageId: 'xpathInjection',
527
+ data: {
528
+ filePath: filename,
529
+ line: String(node.loc?.start.line ?? 0),
530
+ severity: 'HIGH',
531
+ safeAlternative: 'Use parameterized XPath construction with input validation',
532
+ },
533
+ });
534
+ }
535
+ }
536
+ },
537
+
538
+ // Check variable assignments with XPath expressions
539
+ VariableDeclarator(node: TSESTree.VariableDeclarator) {
540
+ if (!node.init || node.id.type !== 'Identifier') {
541
+ return;
542
+ }
543
+
544
+ const varName = node.id.name;
545
+
546
+ // Track variables that are assigned the result of sanitization functions
547
+ if (node.init.type === 'CallExpression' &&
548
+ node.init.callee.type === 'Identifier' &&
549
+ (xpathValidationFunctions.includes(node.init.callee.name) || trustedSanitizers.includes(node.init.callee.name))) {
550
+ validatedVariables.add(varName);
551
+ }
552
+
553
+ const varNameLower = varName.toLowerCase();
554
+ if (!varNameLower.includes('xpath') && !varNameLower.includes('query') && !varNameLower.includes('path')) {
555
+ return;
556
+ }
557
+
558
+ // Check if assigned value contains dangerous XPath
559
+ if (node.init.type === 'Literal' && typeof node.init.value === 'string') {
560
+ if (containsDangerousXpath(node.init.value)) {
561
+ // FALSE POSITIVE REDUCTION
562
+ if (safetyChecker.isSafe(node.init, context) || hasSafeAnnotationOnStatement(node)) {
563
+ return;
564
+ }
565
+
566
+ context.report({
567
+ node: node.init,
568
+ messageId: 'dangerousXpathExpression',
569
+ data: {
570
+ filePath: filename,
571
+ line: String(node.loc?.start.line ?? 0),
572
+ },
573
+ });
574
+ }
575
+ } else if (isUntrustedXpathInput(node.init) && !isSafeXpathConstruction(node.init)) {
576
+ /* c8 ignore start -- safetyChecker requires JSDoc annotations not testable via RuleTester */
577
+ if (safetyChecker.isSafe(node.init, context)) {
578
+ return;
579
+ }
580
+ /* c8 ignore stop */
581
+
582
+ context.report({
583
+ node: node.init,
584
+ messageId: 'xpathInjection',
585
+ data: {
586
+ filePath: filename,
587
+ line: String(node.loc?.start.line ?? 0),
588
+ severity: 'MEDIUM',
589
+ safeAlternative: 'Use safe XPath construction methods',
590
+ },
591
+ });
592
+ }
593
+ }
594
+ };
595
+ },
596
+ });