shield360 1.0.1 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (424) hide show
  1. package/README.md +392 -37
  2. package/dist/__tests__/build-info.test.d.ts +1 -0
  3. package/dist/__tests__/build-info.test.js +196 -0
  4. package/dist/__tests__/build-info.test.js.map +1 -0
  5. package/dist/__tests__/code-location.test.d.ts +1 -0
  6. package/dist/__tests__/code-location.test.js +180 -0
  7. package/dist/__tests__/code-location.test.js.map +1 -0
  8. package/dist/__tests__/masking.test.d.ts +1 -0
  9. package/dist/__tests__/masking.test.js +66 -0
  10. package/dist/__tests__/masking.test.js.map +1 -0
  11. package/dist/__tests__/pricing-claude-5.test.js +3 -0
  12. package/dist/__tests__/pricing-claude-5.test.js.map +1 -1
  13. package/dist/__tests__/register.e2e.test.d.ts +1 -0
  14. package/dist/__tests__/register.e2e.test.js +264 -0
  15. package/dist/__tests__/register.e2e.test.js.map +1 -0
  16. package/dist/__tests__/register.test.js +60 -0
  17. package/dist/__tests__/register.test.js.map +1 -1
  18. package/dist/agents/__tests__/agents.test.d.ts +1 -0
  19. package/dist/agents/__tests__/agents.test.js +529 -0
  20. package/dist/agents/__tests__/agents.test.js.map +1 -0
  21. package/dist/agents/index.d.ts +15 -0
  22. package/dist/agents/index.js +25 -0
  23. package/dist/agents/index.js.map +1 -0
  24. package/dist/agents/passport.d.ts +92 -0
  25. package/dist/agents/passport.js +301 -0
  26. package/dist/agents/passport.js.map +1 -0
  27. package/dist/agents/policy.d.ts +24 -0
  28. package/dist/agents/policy.js +93 -0
  29. package/dist/agents/policy.js.map +1 -0
  30. package/dist/agents/replay.d.ts +20 -0
  31. package/dist/agents/replay.js +47 -0
  32. package/dist/agents/replay.js.map +1 -0
  33. package/dist/agents/report.d.ts +30 -0
  34. package/dist/agents/report.js +93 -0
  35. package/dist/agents/report.js.map +1 -0
  36. package/dist/agents/types.d.ts +148 -0
  37. package/dist/agents/types.js +37 -0
  38. package/dist/agents/types.js.map +1 -0
  39. package/dist/agents/verifier.d.ts +33 -0
  40. package/dist/agents/verifier.js +276 -0
  41. package/dist/agents/verifier.js.map +1 -0
  42. package/dist/ai-security/__tests__/bench.test.d.ts +1 -0
  43. package/dist/ai-security/__tests__/bench.test.js +50 -0
  44. package/dist/ai-security/__tests__/bench.test.js.map +1 -0
  45. package/dist/ai-security/__tests__/checks.test.d.ts +1 -0
  46. package/dist/ai-security/__tests__/checks.test.js +248 -0
  47. package/dist/ai-security/__tests__/checks.test.js.map +1 -0
  48. package/dist/ai-security/__tests__/config.test.d.ts +1 -0
  49. package/dist/ai-security/__tests__/config.test.js +164 -0
  50. package/dist/ai-security/__tests__/config.test.js.map +1 -0
  51. package/dist/ai-security/__tests__/detection.test.d.ts +1 -0
  52. package/dist/ai-security/__tests__/detection.test.js +114 -0
  53. package/dist/ai-security/__tests__/detection.test.js.map +1 -0
  54. package/dist/ai-security/__tests__/fixtures.d.ts +8 -0
  55. package/dist/ai-security/__tests__/fixtures.js +30 -0
  56. package/dist/ai-security/__tests__/fixtures.js.map +1 -0
  57. package/dist/ai-security/__tests__/hooks.test.d.ts +1 -0
  58. package/dist/ai-security/__tests__/hooks.test.js +174 -0
  59. package/dist/ai-security/__tests__/hooks.test.js.map +1 -0
  60. package/dist/ai-security/__tests__/stream.test.d.ts +1 -0
  61. package/dist/ai-security/__tests__/stream.test.js +85 -0
  62. package/dist/ai-security/__tests__/stream.test.js.map +1 -0
  63. package/dist/ai-security/config.d.ts +94 -0
  64. package/dist/ai-security/config.js +241 -0
  65. package/dist/ai-security/config.js.map +1 -0
  66. package/dist/ai-security/context.d.ts +45 -0
  67. package/dist/ai-security/context.js +108 -0
  68. package/dist/ai-security/context.js.map +1 -0
  69. package/dist/ai-security/custom-kinds.d.ts +23 -0
  70. package/dist/ai-security/custom-kinds.js +97 -0
  71. package/dist/ai-security/custom-kinds.js.map +1 -0
  72. package/dist/ai-security/events.d.ts +77 -0
  73. package/dist/ai-security/events.js +153 -0
  74. package/dist/ai-security/events.js.map +1 -0
  75. package/dist/ai-security/hooks.d.ts +48 -0
  76. package/dist/ai-security/hooks.js +461 -0
  77. package/dist/ai-security/hooks.js.map +1 -0
  78. package/dist/ai-security/index.d.ts +209 -0
  79. package/dist/ai-security/index.js +587 -0
  80. package/dist/ai-security/index.js.map +1 -0
  81. package/dist/ai-security/injection-rules.json +1024 -0
  82. package/dist/ai-security/injection.d.ts +46 -0
  83. package/dist/ai-security/injection.js +635 -0
  84. package/dist/ai-security/injection.js.map +1 -0
  85. package/dist/ai-security/jailbreak.d.ts +38 -0
  86. package/dist/ai-security/jailbreak.js +73 -0
  87. package/dist/ai-security/jailbreak.js.map +1 -0
  88. package/dist/ai-security/limits.d.ts +84 -0
  89. package/dist/ai-security/limits.js +195 -0
  90. package/dist/ai-security/limits.js.map +1 -0
  91. package/dist/ai-security/mcp.d.ts +82 -0
  92. package/dist/ai-security/mcp.js +150 -0
  93. package/dist/ai-security/mcp.js.map +1 -0
  94. package/dist/ai-security/output.d.ts +107 -0
  95. package/dist/ai-security/output.js +390 -0
  96. package/dist/ai-security/output.js.map +1 -0
  97. package/dist/ai-security/policy.d.ts +125 -0
  98. package/dist/ai-security/policy.js +196 -0
  99. package/dist/ai-security/policy.js.map +1 -0
  100. package/dist/ai-security/rag.d.ts +70 -0
  101. package/dist/ai-security/rag.js +174 -0
  102. package/dist/ai-security/rag.js.map +1 -0
  103. package/dist/ai-security/tool-rules.json +203 -0
  104. package/dist/ai-security/tools.d.ts +46 -0
  105. package/dist/ai-security/tools.js +62 -0
  106. package/dist/ai-security/tools.js.map +1 -0
  107. package/dist/budgets/__tests__/budgets.test.d.ts +1 -0
  108. package/dist/budgets/__tests__/budgets.test.js +134 -0
  109. package/dist/budgets/__tests__/budgets.test.js.map +1 -0
  110. package/dist/budgets/auto.d.ts +25 -0
  111. package/dist/budgets/auto.js +63 -0
  112. package/dist/budgets/auto.js.map +1 -0
  113. package/dist/budgets/index.d.ts +110 -0
  114. package/dist/budgets/index.js +239 -0
  115. package/dist/budgets/index.js.map +1 -0
  116. package/dist/config.js +1 -1
  117. package/dist/config.js.map +1 -1
  118. package/dist/customer/__tests__/customer.test.d.ts +1 -0
  119. package/dist/customer/__tests__/customer.test.js +155 -0
  120. package/dist/customer/__tests__/customer.test.js.map +1 -0
  121. package/dist/customer/index.d.ts +48 -0
  122. package/dist/customer/index.js +132 -0
  123. package/dist/customer/index.js.map +1 -0
  124. package/dist/feedback/__tests__/feedback.test.d.ts +1 -0
  125. package/dist/feedback/__tests__/feedback.test.js +80 -0
  126. package/dist/feedback/__tests__/feedback.test.js.map +1 -0
  127. package/dist/feedback/index.d.ts +48 -0
  128. package/dist/feedback/index.js +97 -0
  129. package/dist/feedback/index.js.map +1 -0
  130. package/dist/flags/__tests__/flags.test.d.ts +1 -0
  131. package/dist/flags/__tests__/flags.test.js +301 -0
  132. package/dist/flags/__tests__/flags.test.js.map +1 -0
  133. package/dist/flags/client.d.ts +131 -0
  134. package/dist/flags/client.js +301 -0
  135. package/dist/flags/client.js.map +1 -0
  136. package/dist/flags/engine.d.ts +200 -0
  137. package/dist/flags/engine.js +677 -0
  138. package/dist/flags/engine.js.map +1 -0
  139. package/dist/flags/index.d.ts +4 -0
  140. package/dist/flags/index.js +16 -0
  141. package/dist/flags/index.js.map +1 -0
  142. package/dist/guard/__tests__/findings.test.js +28 -9
  143. package/dist/guard/__tests__/findings.test.js.map +1 -1
  144. package/dist/guard/__tests__/report.test.js +67 -0
  145. package/dist/guard/__tests__/report.test.js.map +1 -1
  146. package/dist/guard/base.d.ts +2 -0
  147. package/dist/guard/base.js +4 -0
  148. package/dist/guard/base.js.map +1 -1
  149. package/dist/guard/findings.d.ts +12 -2
  150. package/dist/guard/findings.js +19 -49
  151. package/dist/guard/findings.js.map +1 -1
  152. package/dist/guard/heartbeat.d.ts +34 -0
  153. package/dist/guard/heartbeat.js +83 -0
  154. package/dist/guard/heartbeat.js.map +1 -0
  155. package/dist/guard/integration.d.ts +33 -3
  156. package/dist/guard/integration.js +106 -32
  157. package/dist/guard/integration.js.map +1 -1
  158. package/dist/guard/pipeline.d.ts +10 -1
  159. package/dist/guard/pipeline.js +14 -0
  160. package/dist/guard/pipeline.js.map +1 -1
  161. package/dist/guard/report.d.ts +24 -1
  162. package/dist/guard/report.js +67 -18
  163. package/dist/guard/report.js.map +1 -1
  164. package/dist/index.d.ts +90 -0
  165. package/dist/index.js +225 -3
  166. package/dist/index.js.map +1 -1
  167. package/dist/instrumentation/__tests__/langchain-wrapper.test.js +1 -1
  168. package/dist/instrumentation/__tests__/langchain-wrapper.test.js.map +1 -1
  169. package/dist/instrumentation/anthropic/wrapper.js +4 -0
  170. package/dist/instrumentation/anthropic/wrapper.js.map +1 -1
  171. package/dist/instrumentation/mcp/wrapper.js +7 -1
  172. package/dist/instrumentation/mcp/wrapper.js.map +1 -1
  173. package/dist/instrumentation/openai/wrapper.js +6 -0
  174. package/dist/instrumentation/openai/wrapper.js.map +1 -1
  175. package/dist/masking.d.ts +42 -0
  176. package/dist/masking.js +197 -0
  177. package/dist/masking.js.map +1 -0
  178. package/dist/otel/__tests__/app-logs-safety.test.d.ts +1 -0
  179. package/dist/otel/__tests__/app-logs-safety.test.js +129 -0
  180. package/dist/otel/__tests__/app-logs-safety.test.js.map +1 -0
  181. package/dist/otel/__tests__/app-logs.test.d.ts +1 -0
  182. package/dist/otel/__tests__/app-logs.test.js +269 -0
  183. package/dist/otel/__tests__/app-logs.test.js.map +1 -0
  184. package/dist/otel/__tests__/log-auto.test.d.ts +1 -0
  185. package/dist/otel/__tests__/log-auto.test.js +125 -0
  186. package/dist/otel/__tests__/log-auto.test.js.map +1 -0
  187. package/dist/otel/__tests__/log-bridges.test.d.ts +1 -0
  188. package/dist/otel/__tests__/log-bridges.test.js +170 -0
  189. package/dist/otel/__tests__/log-bridges.test.js.map +1 -0
  190. package/dist/otel/__tests__/system-metrics.test.d.ts +1 -0
  191. package/dist/otel/__tests__/system-metrics.test.js +79 -0
  192. package/dist/otel/__tests__/system-metrics.test.js.map +1 -0
  193. package/dist/otel/app-logs.d.ts +80 -0
  194. package/dist/otel/app-logs.js +195 -0
  195. package/dist/otel/app-logs.js.map +1 -0
  196. package/dist/otel/build-info.d.ts +23 -0
  197. package/dist/otel/build-info.js +176 -0
  198. package/dist/otel/build-info.js.map +1 -0
  199. package/dist/otel/code-location.d.ts +49 -0
  200. package/dist/otel/code-location.js +233 -0
  201. package/dist/otel/code-location.js.map +1 -0
  202. package/dist/otel/events.d.ts +1 -0
  203. package/dist/otel/events.js +21 -12
  204. package/dist/otel/events.js.map +1 -1
  205. package/dist/otel/log-auto.d.ts +44 -0
  206. package/dist/otel/log-auto.js +200 -0
  207. package/dist/otel/log-auto.js.map +1 -0
  208. package/dist/otel/log-bridges.d.ts +54 -0
  209. package/dist/otel/log-bridges.js +307 -0
  210. package/dist/otel/log-bridges.js.map +1 -0
  211. package/dist/otel/system-metrics.d.ts +39 -0
  212. package/dist/otel/system-metrics.js +166 -0
  213. package/dist/otel/system-metrics.js.map +1 -0
  214. package/dist/otel/tracing.js +12 -1
  215. package/dist/otel/tracing.js.map +1 -1
  216. package/dist/pricing.json +100 -42
  217. package/dist/protect/__tests__/protect.test.d.ts +1 -0
  218. package/dist/protect/__tests__/protect.test.js +210 -0
  219. package/dist/protect/__tests__/protect.test.js.map +1 -0
  220. package/dist/protect/index.d.ts +103 -0
  221. package/dist/protect/index.js +196 -0
  222. package/dist/protect/index.js.map +1 -0
  223. package/dist/protect/mcp.d.ts +13 -0
  224. package/dist/protect/mcp.js +49 -0
  225. package/dist/protect/mcp.js.map +1 -0
  226. package/dist/protect/mode.d.ts +89 -0
  227. package/dist/protect/mode.js +134 -0
  228. package/dist/protect/mode.js.map +1 -0
  229. package/dist/rasp/__tests__/auto-http.test.d.ts +1 -0
  230. package/dist/rasp/__tests__/auto-http.test.js +136 -0
  231. package/dist/rasp/__tests__/auto-http.test.js.map +1 -0
  232. package/dist/rasp/__tests__/baseline.test.d.ts +1 -0
  233. package/dist/rasp/__tests__/baseline.test.js +86 -0
  234. package/dist/rasp/__tests__/baseline.test.js.map +1 -0
  235. package/dist/rasp/__tests__/benign-corpus.test.d.ts +1 -0
  236. package/dist/rasp/__tests__/benign-corpus.test.js +68 -0
  237. package/dist/rasp/__tests__/benign-corpus.test.js.map +1 -0
  238. package/dist/rasp/__tests__/capture-context.test.d.ts +1 -0
  239. package/dist/rasp/__tests__/capture-context.test.js +135 -0
  240. package/dist/rasp/__tests__/capture-context.test.js.map +1 -0
  241. package/dist/rasp/__tests__/code-hook.test.d.ts +1 -0
  242. package/dist/rasp/__tests__/code-hook.test.js +218 -0
  243. package/dist/rasp/__tests__/code-hook.test.js.map +1 -0
  244. package/dist/rasp/__tests__/config-client.test.d.ts +1 -0
  245. package/dist/rasp/__tests__/config-client.test.js +283 -0
  246. package/dist/rasp/__tests__/config-client.test.js.map +1 -0
  247. package/dist/rasp/__tests__/corpus.d.ts +13 -0
  248. package/dist/rasp/__tests__/corpus.js +111 -0
  249. package/dist/rasp/__tests__/corpus.js.map +1 -0
  250. package/dist/rasp/__tests__/custom-rules.test.d.ts +1 -0
  251. package/dist/rasp/__tests__/custom-rules.test.js +276 -0
  252. package/dist/rasp/__tests__/custom-rules.test.js.map +1 -0
  253. package/dist/rasp/__tests__/db-hook.test.d.ts +1 -0
  254. package/dist/rasp/__tests__/db-hook.test.js +438 -0
  255. package/dist/rasp/__tests__/db-hook.test.js.map +1 -0
  256. package/dist/rasp/__tests__/deception.test.d.ts +1 -0
  257. package/dist/rasp/__tests__/deception.test.js +567 -0
  258. package/dist/rasp/__tests__/deception.test.js.map +1 -0
  259. package/dist/rasp/__tests__/detect.test.d.ts +1 -0
  260. package/dist/rasp/__tests__/detect.test.js +276 -0
  261. package/dist/rasp/__tests__/detect.test.js.map +1 -0
  262. package/dist/rasp/__tests__/esm-exports.test.d.ts +1 -0
  263. package/dist/rasp/__tests__/esm-exports.test.js +20 -0
  264. package/dist/rasp/__tests__/esm-exports.test.js.map +1 -0
  265. package/dist/rasp/__tests__/fs-hook.test.d.ts +1 -0
  266. package/dist/rasp/__tests__/fs-hook.test.js +241 -0
  267. package/dist/rasp/__tests__/fs-hook.test.js.map +1 -0
  268. package/dist/rasp/__tests__/hook-contracts.test.d.ts +1 -0
  269. package/dist/rasp/__tests__/hook-contracts.test.js +201 -0
  270. package/dist/rasp/__tests__/hook-contracts.test.js.map +1 -0
  271. package/dist/rasp/__tests__/hook-kit.d.ts +42 -0
  272. package/dist/rasp/__tests__/hook-kit.js +139 -0
  273. package/dist/rasp/__tests__/hook-kit.js.map +1 -0
  274. package/dist/rasp/__tests__/http-hook.test.d.ts +1 -0
  275. package/dist/rasp/__tests__/http-hook.test.js +250 -0
  276. package/dist/rasp/__tests__/http-hook.test.js.map +1 -0
  277. package/dist/rasp/__tests__/iast.test.d.ts +1 -0
  278. package/dist/rasp/__tests__/iast.test.js +361 -0
  279. package/dist/rasp/__tests__/iast.test.js.map +1 -0
  280. package/dist/rasp/__tests__/include-hook.test.d.ts +1 -0
  281. package/dist/rasp/__tests__/include-hook.test.js +122 -0
  282. package/dist/rasp/__tests__/include-hook.test.js.map +1 -0
  283. package/dist/rasp/__tests__/middleware.test.d.ts +1 -0
  284. package/dist/rasp/__tests__/middleware.test.js +302 -0
  285. package/dist/rasp/__tests__/middleware.test.js.map +1 -0
  286. package/dist/rasp/__tests__/process-hook.test.d.ts +1 -0
  287. package/dist/rasp/__tests__/process-hook.test.js +238 -0
  288. package/dist/rasp/__tests__/process-hook.test.js.map +1 -0
  289. package/dist/rasp/__tests__/reporter.test.d.ts +1 -0
  290. package/dist/rasp/__tests__/reporter.test.js +114 -0
  291. package/dist/rasp/__tests__/reporter.test.js.map +1 -0
  292. package/dist/rasp/__tests__/route.test.d.ts +1 -0
  293. package/dist/rasp/__tests__/route.test.js +46 -0
  294. package/dist/rasp/__tests__/route.test.js.map +1 -0
  295. package/dist/rasp/__tests__/rule-expr.test.d.ts +1 -0
  296. package/dist/rasp/__tests__/rule-expr.test.js +151 -0
  297. package/dist/rasp/__tests__/rule-expr.test.js.map +1 -0
  298. package/dist/rasp/__tests__/rule-phases.test.d.ts +1 -0
  299. package/dist/rasp/__tests__/rule-phases.test.js +271 -0
  300. package/dist/rasp/__tests__/rule-phases.test.js.map +1 -0
  301. package/dist/rasp/__tests__/sinks-hook.test.d.ts +1 -0
  302. package/dist/rasp/__tests__/sinks-hook.test.js +177 -0
  303. package/dist/rasp/__tests__/sinks-hook.test.js.map +1 -0
  304. package/dist/rasp/__tests__/targets.test.d.ts +1 -0
  305. package/dist/rasp/__tests__/targets.test.js +82 -0
  306. package/dist/rasp/__tests__/targets.test.js.map +1 -0
  307. package/dist/rasp/__tests__/template-hook.test.d.ts +1 -0
  308. package/dist/rasp/__tests__/template-hook.test.js +254 -0
  309. package/dist/rasp/__tests__/template-hook.test.js.map +1 -0
  310. package/dist/rasp/__tests__/upload.test.d.ts +1 -0
  311. package/dist/rasp/__tests__/upload.test.js +81 -0
  312. package/dist/rasp/__tests__/upload.test.js.map +1 -0
  313. package/dist/rasp/__tests__/vpatch-engine.test.d.ts +1 -0
  314. package/dist/rasp/__tests__/vpatch-engine.test.js +177 -0
  315. package/dist/rasp/__tests__/vpatch-engine.test.js.map +1 -0
  316. package/dist/rasp/auto-http.d.ts +6 -0
  317. package/dist/rasp/auto-http.js +194 -0
  318. package/dist/rasp/auto-http.js.map +1 -0
  319. package/dist/rasp/baseline.d.ts +35 -0
  320. package/dist/rasp/baseline.js +91 -0
  321. package/dist/rasp/baseline.js.map +1 -0
  322. package/dist/rasp/capture.d.ts +76 -0
  323. package/dist/rasp/capture.js +304 -0
  324. package/dist/rasp/capture.js.map +1 -0
  325. package/dist/rasp/config-client.d.ts +122 -0
  326. package/dist/rasp/config-client.js +337 -0
  327. package/dist/rasp/config-client.js.map +1 -0
  328. package/dist/rasp/context.d.ts +65 -0
  329. package/dist/rasp/context.js +68 -0
  330. package/dist/rasp/context.js.map +1 -0
  331. package/dist/rasp/custom-rules.d.ts +68 -0
  332. package/dist/rasp/custom-rules.js +222 -0
  333. package/dist/rasp/custom-rules.js.map +1 -0
  334. package/dist/rasp/data/default-rules.json +199 -0
  335. package/dist/rasp/data/default-sinks.json +4 -0
  336. package/dist/rasp/data/dnslog-domains.json +11 -0
  337. package/dist/rasp/deception.d.ts +70 -0
  338. package/dist/rasp/deception.js +220 -0
  339. package/dist/rasp/deception.js.map +1 -0
  340. package/dist/rasp/detect.d.ts +68 -0
  341. package/dist/rasp/detect.js +671 -0
  342. package/dist/rasp/detect.js.map +1 -0
  343. package/dist/rasp/engine.d.ts +107 -0
  344. package/dist/rasp/engine.js +330 -0
  345. package/dist/rasp/engine.js.map +1 -0
  346. package/dist/rasp/hooks/code.d.ts +20 -0
  347. package/dist/rasp/hooks/code.js +334 -0
  348. package/dist/rasp/hooks/code.js.map +1 -0
  349. package/dist/rasp/hooks/db.d.ts +48 -0
  350. package/dist/rasp/hooks/db.js +322 -0
  351. package/dist/rasp/hooks/db.js.map +1 -0
  352. package/dist/rasp/hooks/esm.d.ts +7 -0
  353. package/dist/rasp/hooks/esm.js +18 -0
  354. package/dist/rasp/hooks/esm.js.map +1 -0
  355. package/dist/rasp/hooks/fs.d.ts +3 -0
  356. package/dist/rasp/hooks/fs.js +206 -0
  357. package/dist/rasp/hooks/fs.js.map +1 -0
  358. package/dist/rasp/hooks/http.d.ts +4 -0
  359. package/dist/rasp/hooks/http.js +213 -0
  360. package/dist/rasp/hooks/http.js.map +1 -0
  361. package/dist/rasp/hooks/include.d.ts +9 -0
  362. package/dist/rasp/hooks/include.js +79 -0
  363. package/dist/rasp/hooks/include.js.map +1 -0
  364. package/dist/rasp/hooks/marks.d.ts +2 -0
  365. package/dist/rasp/hooks/marks.js +16 -0
  366. package/dist/rasp/hooks/marks.js.map +1 -0
  367. package/dist/rasp/hooks/process.d.ts +22 -0
  368. package/dist/rasp/hooks/process.js +191 -0
  369. package/dist/rasp/hooks/process.js.map +1 -0
  370. package/dist/rasp/hooks/sinks.d.ts +54 -0
  371. package/dist/rasp/hooks/sinks.js +329 -0
  372. package/dist/rasp/hooks/sinks.js.map +1 -0
  373. package/dist/rasp/hooks/template.d.ts +21 -0
  374. package/dist/rasp/hooks/template.js +152 -0
  375. package/dist/rasp/hooks/template.js.map +1 -0
  376. package/dist/rasp/iast-rules.d.ts +82 -0
  377. package/dist/rasp/iast-rules.js +240 -0
  378. package/dist/rasp/iast-rules.js.map +1 -0
  379. package/dist/rasp/iast-scope.d.ts +29 -0
  380. package/dist/rasp/iast-scope.js +54 -0
  381. package/dist/rasp/iast-scope.js.map +1 -0
  382. package/dist/rasp/iast.d.ts +81 -0
  383. package/dist/rasp/iast.js +272 -0
  384. package/dist/rasp/iast.js.map +1 -0
  385. package/dist/rasp/index.d.ts +52 -0
  386. package/dist/rasp/index.js +280 -0
  387. package/dist/rasp/index.js.map +1 -0
  388. package/dist/rasp/lexers.d.ts +32 -0
  389. package/dist/rasp/lexers.js +444 -0
  390. package/dist/rasp/lexers.js.map +1 -0
  391. package/dist/rasp/middleware.d.ts +155 -0
  392. package/dist/rasp/middleware.js +568 -0
  393. package/dist/rasp/middleware.js.map +1 -0
  394. package/dist/rasp/model-output.d.ts +14 -0
  395. package/dist/rasp/model-output.js +107 -0
  396. package/dist/rasp/model-output.js.map +1 -0
  397. package/dist/rasp/normalize.d.ts +23 -0
  398. package/dist/rasp/normalize.js +140 -0
  399. package/dist/rasp/normalize.js.map +1 -0
  400. package/dist/rasp/reporter.d.ts +60 -0
  401. package/dist/rasp/reporter.js +230 -0
  402. package/dist/rasp/reporter.js.map +1 -0
  403. package/dist/rasp/rule-expr.d.ts +236 -0
  404. package/dist/rasp/rule-expr.js +1253 -0
  405. package/dist/rasp/rule-expr.js.map +1 -0
  406. package/dist/rasp/template.d.ts +53 -0
  407. package/dist/rasp/template.js +336 -0
  408. package/dist/rasp/template.js.map +1 -0
  409. package/dist/rasp/types.d.ts +110 -0
  410. package/dist/rasp/types.js +51 -0
  411. package/dist/rasp/types.js.map +1 -0
  412. package/dist/rasp/vpatch.d.ts +55 -0
  413. package/dist/rasp/vpatch.js +120 -0
  414. package/dist/rasp/vpatch.js.map +1 -0
  415. package/dist/register.js +52 -11
  416. package/dist/register.js.map +1 -1
  417. package/dist/semantic-convention.d.ts +2 -0
  418. package/dist/semantic-convention.js +5 -0
  419. package/dist/semantic-convention.js.map +1 -1
  420. package/dist/types.d.ts +96 -0
  421. package/dist/zero-code.d.ts +8 -0
  422. package/dist/zero-code.js +38 -0
  423. package/dist/zero-code.js.map +1 -0
  424. package/package.json +18 -2
@@ -0,0 +1,671 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.detectTemplate = exports.MAX_XSS_BODY = exports.METADATA_HOSTS = exports.SCRIPT_FILE = exports.DOWNLOADERS = exports.SHELLS = void 0;
7
+ exports.detectSql = detectSql;
8
+ exports.detectNoSql = detectNoSql;
9
+ exports.exeName = exeName;
10
+ exports.detectCommand = detectCommand;
11
+ exports.detectArgv = detectArgv;
12
+ exports.detectShellSpawn = detectShellSpawn;
13
+ exports.shellScriptOf = shellScriptOf;
14
+ exports.normPath = normPath;
15
+ exports.resolvePath = resolvePath;
16
+ exports.underRoot = underRoot;
17
+ exports.targetDirectory = targetDirectory;
18
+ exports.detectPath = detectPath;
19
+ exports.rawUrl = rawUrl;
20
+ exports.isPrivateAddress = isPrivateAddress;
21
+ exports.isIpLiteral = isIpLiteral;
22
+ exports.hostMatches = hostMatches;
23
+ exports.taintOf = taintOf;
24
+ exports.detectSsrf = detectSsrf;
25
+ exports.detectOutbound = detectOutbound;
26
+ exports.taintedData = taintedData;
27
+ exports.detectDeserialization = detectDeserialization;
28
+ exports.detectCode = detectCode;
29
+ exports.detectInclude = detectInclude;
30
+ exports.detectUpload = detectUpload;
31
+ exports.parseDoctype = parseDoctype;
32
+ exports.detectXml = detectXml;
33
+ exports.detectXss = detectXss;
34
+ /**
35
+ * Pure structural detectors (README "Detection algorithms"). Each takes the
36
+ * sink's argument and the inputs in scope and returns a Finding or null. No
37
+ * I/O, no state: the engine decides what a finding does.
38
+ */
39
+ const os_1 = require("os");
40
+ const path_1 = require("path");
41
+ const lexers_1 = require("./lexers");
42
+ const iast_scope_1 = require("./iast-scope");
43
+ const iast_rules_1 = require("./iast-rules");
44
+ const dnslog_domains_json_1 = __importDefault(require("./data/dnslog-domains.json"));
45
+ const reqInputs = (inputs, min) => inputs.filter((i) => i.source === 'request' && i.value.length >= min);
46
+ const modelInputs = (inputs, min) => inputs.filter((i) => i.source === 'model_output' && i.value.length >= min);
47
+ // ---- SQL ----------------------------------------------------------------
48
+ const ANTI_DETECT = lexers_1.SQL_KEYWORDS;
49
+ const COMMA_LIST = /^(, *)?(([a-zA-Z_]\w*|[0-9+\-x.]+) *, *)+([a-zA-Z_]\w*|[0-9+\-x.]+)$/;
50
+ const WRITE_STATEMENTS = new Set('insert update delete drop alter create truncate grant revoke merge replace'.split(' '));
51
+ const isComment = (t) => t.kind === 'comment' || t.kind === 'version_comment';
52
+ function hasStackedAfter(tokens, from) {
53
+ for (const t of from) {
54
+ if (t.kind !== 'op' || t.text !== ';')
55
+ continue;
56
+ const at = tokens.indexOf(t);
57
+ if (tokens.slice(at + 1).some((x) => !isComment(x)))
58
+ return true;
59
+ }
60
+ return false;
61
+ }
62
+ function sqlWholeIsDangerous(tokens) {
63
+ const code = tokens.filter((t) => !isComment(t));
64
+ if (!code.length)
65
+ return false;
66
+ if (code[0].kind === 'word' && WRITE_STATEMENTS.has(code[0].text.toLowerCase()))
67
+ return true;
68
+ for (let i = 0; i < code.length - 1; i++)
69
+ if (code[i].kind === 'op' && code[i].text === ';')
70
+ return true;
71
+ return false;
72
+ }
73
+ function detectSql(query, inputs, dialect = 'generic') {
74
+ const f = detectSqlRules(query, inputs, dialect);
75
+ return f ? { ...f, dialect } : null;
76
+ }
77
+ function detectSqlRules(query, inputs, dialect) {
78
+ if (!query || !inputs.length)
79
+ return null;
80
+ let tokens = null;
81
+ const toks = () => (tokens ?? (tokens = (0, lexers_1.sqlTokens)(query, dialect)));
82
+ const trimmed = query.trim();
83
+ for (const inp of reqInputs(inputs, 3)) {
84
+ const v = inp.value;
85
+ if (v === query || v.trim() === trimmed)
86
+ continue; // allow_full: a SQL console
87
+ const occ = (0, lexers_1.occurrences)(query, v);
88
+ if (!occ.length)
89
+ continue;
90
+ const commaList = COMMA_LIST.test(v);
91
+ for (const idx of occ) {
92
+ const over = (0, lexers_1.overlapping)(toks(), idx, v.length);
93
+ if (!commaList && over.length >= 2) {
94
+ if (over.length >= 10)
95
+ return { attack: 'sql_injection', rule: 'sqli.userinput', input: inp };
96
+ const plain = over.filter((t) => !(t.kind === 'word' && ANTI_DETECT.has(t.text.toLowerCase())));
97
+ if (plain.length >= 2)
98
+ return { attack: 'sql_injection', rule: 'sqli.userinput', input: inp };
99
+ }
100
+ if (hasStackedAfter(toks(), over))
101
+ return { attack: 'sql_injection', rule: 'sqli.stacked', input: inp };
102
+ }
103
+ }
104
+ for (const inp of modelInputs(inputs, 3)) {
105
+ if (inp.value.trim() === trimmed) {
106
+ if (sqlWholeIsDangerous(toks()))
107
+ return { attack: 'sql_injection', rule: 'sqli.model_output', input: inp };
108
+ continue;
109
+ }
110
+ for (const idx of (0, lexers_1.occurrences)(query, inp.value)) {
111
+ if ((0, lexers_1.overlapping)(toks(), idx, inp.value.length).length >= 2)
112
+ return { attack: 'sql_injection', rule: 'sqli.model_output', input: inp };
113
+ }
114
+ }
115
+ (0, iast_scope_1.noteVulnerability)(() => (0, iast_rules_1.vulnSql)(query, inputs, toks)); // passive IAST (iast-rules.ts)
116
+ return null;
117
+ }
118
+ // ---- NoSQL ----------------------------------------------------------------
119
+ function deepEqual(a, b, depth = 0) {
120
+ if (a === b)
121
+ return true;
122
+ if (depth > 32 || typeof a !== 'object' || typeof b !== 'object' || a === null || b === null)
123
+ return false;
124
+ if (Array.isArray(a) !== Array.isArray(b))
125
+ return false;
126
+ const ka = Object.keys(a);
127
+ const kb = Object.keys(b);
128
+ if (ka.length !== kb.length)
129
+ return false;
130
+ return ka.every((k) => deepEqual(a[k], b[k], depth + 1));
131
+ }
132
+ function treeContains(tree, obj, depth = 0) {
133
+ if (tree === null || typeof tree !== 'object' || depth > 32)
134
+ return false;
135
+ if (tree === obj || deepEqual(tree, obj))
136
+ return true;
137
+ return Object.values(tree).some((v) => treeContains(v, obj, depth + 1));
138
+ }
139
+ function detectNoSql(doc, trees, inputs) {
140
+ let found = null;
141
+ const walk = (node, depth) => {
142
+ if (found || node === null || typeof node !== 'object' || depth > 32)
143
+ return;
144
+ const entries = Object.entries(node);
145
+ if (!Array.isArray(node) && entries.some(([k]) => k.startsWith('$')) && trees.some((t) => treeContains(t, node))) {
146
+ found = { attack: 'nosql_injection', rule: 'nosqli.operator' };
147
+ return;
148
+ }
149
+ for (const [k, v] of entries) {
150
+ if ((k === '$where' || k === '$function') && !found) {
151
+ const code = typeof v === 'string' ? v : v && typeof v === 'object' && typeof v.body === 'string' ? v.body : '';
152
+ const hit = code ? detectCode(code, inputs) : null;
153
+ if (hit)
154
+ found = { attack: 'nosql_injection', rule: 'nosqli.where', input: hit.input };
155
+ }
156
+ walk(v, depth + 1);
157
+ }
158
+ };
159
+ walk(doc, 0);
160
+ return found;
161
+ }
162
+ // ---- Command ----------------------------------------------------------------
163
+ exports.SHELLS = new Set('sh bash zsh dash ksh fish csh tcsh cmd powershell pwsh'.split(' '));
164
+ exports.DOWNLOADERS = new Set(['curl', 'wget']);
165
+ const MULTI_OPS = new Set([';', '&&', '||', '|', '`', '$(']);
166
+ function exeName(p) {
167
+ const base = p.replace(/\\/g, '/').split('/').pop() || '';
168
+ return base.toLowerCase().replace(/\.exe$/, '');
169
+ }
170
+ function unquoteWord(w) {
171
+ return w.replace(/^['"]|['"]$/g, '');
172
+ }
173
+ function detectCommand(command, inputs) {
174
+ if (!command || !inputs.length)
175
+ return null;
176
+ const { tokens, inSingle } = (0, lexers_1.shellTokens)(command);
177
+ const trimmed = command.trim();
178
+ for (const inp of reqInputs(inputs, 3)) {
179
+ for (const idx of (0, lexers_1.occurrences)(command, inp.value)) {
180
+ if ((0, lexers_1.overlapping)(tokens, idx, inp.value.length).length >= 2)
181
+ return { attack: 'command_injection', rule: 'cmdi.userinput', input: inp };
182
+ }
183
+ }
184
+ for (const inp of reqInputs(inputs, 3)) {
185
+ const v = inp.value;
186
+ if (v.includes('${IFS}') || v.includes('$IFS')) {
187
+ if (command.includes(v))
188
+ return { attack: 'command_injection', rule: 'cmdi.substitution', input: inp };
189
+ }
190
+ if (v.includes('`') || v.includes('$(')) {
191
+ for (const idx of (0, lexers_1.occurrences)(command, v)) {
192
+ for (let k = idx; k < idx + v.length; k++) {
193
+ const sub = command[k] === '`' || (command[k] === '$' && command[k + 1] === '(');
194
+ if (sub && !inSingle[k])
195
+ return { attack: 'command_injection', rule: 'cmdi.substitution', input: inp };
196
+ }
197
+ }
198
+ }
199
+ }
200
+ for (const inp of reqInputs(inputs, 1))
201
+ if (inp.value.trim() === trimmed)
202
+ return { attack: 'command_injection', rule: 'cmdi.full', input: inp };
203
+ for (const inp of modelInputs(inputs, 3)) {
204
+ if (inp.value.trim() === trimmed) {
205
+ if (tokens.some((t) => t.kind === 'op' && MULTI_OPS.has(t.text)))
206
+ return { attack: 'command_injection', rule: 'cmdi.model_output', input: inp };
207
+ continue;
208
+ }
209
+ for (const idx of (0, lexers_1.occurrences)(command, inp.value)) {
210
+ if ((0, lexers_1.overlapping)(tokens, idx, inp.value.length).length >= 2)
211
+ return { attack: 'command_injection', rule: 'cmdi.model_output', input: inp };
212
+ }
213
+ }
214
+ (0, iast_scope_1.noteVulnerability)(() => (0, iast_rules_1.vulnShell)(command, inputs, tokens)); // passive IAST
215
+ return null;
216
+ }
217
+ /** argv spawns: the executable equals an input. */
218
+ function detectArgv(argv, inputs) {
219
+ if (!argv.length)
220
+ return null;
221
+ for (const inp of inputs)
222
+ if (inp.value.length >= 1 && inp.value === argv[0])
223
+ return { attack: 'command_injection', rule: 'cmdi.executable', input: inp };
224
+ // Passive IAST: a `sh -c <script>` spawn's script is checked as shell text instead.
225
+ (0, iast_scope_1.noteVulnerability)(() => (shellScriptOf(argv) ? null : (0, iast_rules_1.vulnArgv)(argv, inputs)));
226
+ return null;
227
+ }
228
+ /** shell_spawn: a shell or downloader started during a request, or curl|sh at any time. */
229
+ function detectShellSpawn(opts) {
230
+ const allowed = new Set(opts.allow.map(exeName));
231
+ if (opts.command) {
232
+ const words = (0, lexers_1.shellTokens)(opts.command).tokens;
233
+ for (let i = 0; i < words.length; i++) {
234
+ if (words[i].kind !== 'word' || !exports.DOWNLOADERS.has(exeName(unquoteWord(words[i].text))))
235
+ continue;
236
+ for (let k = i + 1; k < words.length - 1; k++) {
237
+ if (words[k].kind === 'op' && words[k].text === '|' && words[k + 1].kind === 'word' && exports.SHELLS.has(exeName(unquoteWord(words[k + 1].text)))) {
238
+ return { attack: 'shell_spawn', rule: 'shell_spawn.download_exec' };
239
+ }
240
+ }
241
+ }
242
+ }
243
+ if (!opts.inRequest)
244
+ return null;
245
+ let name = opts.argv0 ? exeName(opts.argv0) : '';
246
+ if (!name && opts.command) {
247
+ const first = (0, lexers_1.shellTokens)(opts.command).tokens.find((t) => t.kind === 'word');
248
+ name = first ? exeName(unquoteWord(first.text)) : '';
249
+ }
250
+ if (name && (exports.SHELLS.has(name) || exports.DOWNLOADERS.has(name)) && !allowed.has(name))
251
+ return { attack: 'shell_spawn', rule: 'shell_spawn.shell', target: name };
252
+ return null;
253
+ }
254
+ /** The script of `sh -c <script>` style argv, if any. */
255
+ function shellScriptOf(argv) {
256
+ if (argv.length < 3 || !exports.SHELLS.has(exeName(argv[0])))
257
+ return null;
258
+ const i = argv.findIndex((a, k) => k > 0 && (a === '-c' || a.toLowerCase() === '/c' || a.toLowerCase() === '-command'));
259
+ return i > 0 && i + 1 < argv.length ? argv.slice(i + 1).join(' ') : null;
260
+ }
261
+ // ---- Path ----------------------------------------------------------------
262
+ function normPath(p) {
263
+ let s = p.replace(/\\/g, '/');
264
+ const unc = s.startsWith('//');
265
+ while (s.includes('/./'))
266
+ s = s.replace('/./', '/');
267
+ s = s.replace(/\/{2,}/g, '/');
268
+ return unc ? '/' + s : s;
269
+ }
270
+ function resolvePath(p, cwd = process.cwd()) {
271
+ const s = p.replace(/\\/g, '/');
272
+ const abs = s.startsWith('/') || /^[A-Za-z]:\//.test(s) ? s : `${cwd.replace(/\\/g, '/')}/${s}`;
273
+ const drive = /^[A-Za-z]:/.test(abs) ? abs.slice(0, 2) : '';
274
+ return drive + path_1.posix.normalize('/' + abs.slice(drive.length)).replace(/\/$/, '') || '/';
275
+ }
276
+ const SENSITIVE = ['/etc/passwd', '/etc/shadow', '/proc/self/environ', '/root/.bash_history', '/var/run/secrets/kubernetes.io/serviceaccount/token'];
277
+ exports.SCRIPT_FILE = /\.(aspx?|jspx?|php[3-7]?|phar|phtml|sh|bash|py|pyc|pl|rb|so|dll|dylib|exe|cgi|js|mjs|cjs)\.?$/i;
278
+ function underRoot(resolved, root) {
279
+ const r = resolvePath(root);
280
+ return resolved === r || resolved.startsWith(r.endsWith('/') ? r : r + '/');
281
+ }
282
+ /** The directory path.outside_root reports: the resolved path up to its last `/` (README "Allow-list targets"). */
283
+ function targetDirectory(resolved) {
284
+ const dir = resolved.slice(0, Math.max(0, resolved.lastIndexOf('/')));
285
+ return dir === '' || /^[A-Za-z]:$/.test(dir) ? dir + '/' : dir;
286
+ }
287
+ function detectPath(path, op, inputs, fileRoots = [], inRequest = true) {
288
+ if (typeof path !== 'string' || !path)
289
+ return null;
290
+ const np = normPath(path);
291
+ const resolved = resolvePath(path);
292
+ const writes = op === 'write' || op === 'append' || op === 'rename' || op === 'open';
293
+ if (writes && /::\$(DATA|INDEX)$/i.test(path))
294
+ return { attack: 'file_write', rule: 'file_write.ntfs' };
295
+ const cands = reqInputs(inputs, 3).concat(modelInputs(inputs, 3));
296
+ for (const inp of cands) {
297
+ const ni = normPath(inp.value);
298
+ if (ni.includes('../') && (np.endsWith(ni) || np.includes(ni)))
299
+ return { attack: 'path_traversal', rule: 'path.traversal', input: inp };
300
+ const absolute = ni.startsWith('/') || /^[A-Za-z]:\//.test(ni) || inp.value.startsWith('file://');
301
+ if (absolute) {
302
+ const target = inp.value.startsWith('file://') ? normPath(inp.value.slice(7)) : ni;
303
+ if (np === target || np.endsWith(target))
304
+ return { attack: 'path_traversal', rule: 'path.absolute', input: inp };
305
+ }
306
+ const nul = inp.value.indexOf('\0');
307
+ if (nul > 0 && path.includes(inp.value.slice(0, nul)))
308
+ return { attack: 'path_traversal', rule: 'path.nullbyte', input: inp };
309
+ }
310
+ const contained = cands.find((i) => path.includes(i.value) || np.includes(normPath(i.value)));
311
+ if (contained && fileRoots.length && !fileRoots.some((r) => underRoot(resolved, r))) {
312
+ return { attack: 'path_traversal', rule: 'path.outside_root', input: contained, target: targetDirectory(resolved) };
313
+ }
314
+ if (contained) {
315
+ const home = (0, os_1.homedir)().replace(/\\/g, '/');
316
+ if (SENSITIVE.includes(resolved) || resolved === `${home}/.ssh/id_rsa` || resolved.endsWith('/.ssh/id_rsa')) {
317
+ return { attack: 'path_traversal', rule: 'path.sensitive', input: contained };
318
+ }
319
+ }
320
+ if (writes && inRequest && exports.SCRIPT_FILE.test(resolved.split('/').pop() || '')) {
321
+ if (contained || fileRoots.some((r) => underRoot(resolved, r)) || underRoot(resolved, (0, os_1.tmpdir)())) {
322
+ return { attack: 'file_write', rule: 'file_write.script', input: contained };
323
+ }
324
+ }
325
+ (0, iast_scope_1.noteVulnerability)(() => (0, iast_rules_1.vulnPath)(np, inputs, normPath)); // passive IAST
326
+ return null;
327
+ }
328
+ // ---- SSRF ----------------------------------------------------------------
329
+ const SSRF_PROTOCOLS = new Set('file gopher dict ftp jar netdoc ldap ldaps php phar expect tftp'.split(' '));
330
+ exports.METADATA_HOSTS = ['169.254.169.254', 'fd00:ec2::254', '100.100.100.200', '168.63.129.16', '169.254.170.2', 'metadata.google.internal', 'metadata'];
331
+ /** Scheme and raw host as written (the WHATWG parser would rewrite numeric hosts). */
332
+ function rawUrl(url) {
333
+ const m = /^([A-Za-z][A-Za-z0-9+.-]*):/.exec(url);
334
+ if (!m)
335
+ return null;
336
+ const scheme = m[1].toLowerCase();
337
+ let rest = url.slice(m[0].length);
338
+ if (!rest.startsWith('//'))
339
+ return { scheme, host: '' };
340
+ rest = rest.slice(2);
341
+ const end = rest.search(/[/?#\\]/);
342
+ let auth = end < 0 ? rest : rest.slice(0, end);
343
+ const at = auth.lastIndexOf('@');
344
+ if (at >= 0)
345
+ auth = auth.slice(at + 1);
346
+ let host = auth;
347
+ if (host.startsWith('['))
348
+ host = host.slice(1, host.indexOf(']') < 0 ? undefined : host.indexOf(']'));
349
+ else if (host.includes(':'))
350
+ host = host.slice(0, host.indexOf(':'));
351
+ return { scheme, host: host.toLowerCase() };
352
+ }
353
+ function parseV4(s) {
354
+ const p = s.split('.');
355
+ if (p.length !== 4)
356
+ return null;
357
+ const n = p.map((x) => (/^(0|[1-9]\d{0,2})$/.test(x) ? Number(x) : NaN));
358
+ return n.every((x) => x >= 0 && x <= 255) ? n : null;
359
+ }
360
+ function parseV6(s) {
361
+ // Returns 16 bytes, or null.
362
+ if (!s.includes(':'))
363
+ return null;
364
+ let tail = [];
365
+ let str = s;
366
+ const lastColon = str.lastIndexOf(':');
367
+ const v4 = parseV4(str.slice(lastColon + 1));
368
+ if (v4) {
369
+ tail = v4;
370
+ str = str.slice(0, lastColon) + ':0:0';
371
+ }
372
+ const halves = str.split('::');
373
+ if (halves.length > 2)
374
+ return null;
375
+ const parse = (h) => (h ? h.split(':').map((x) => (/^[0-9a-f]{1,4}$/i.test(x) ? parseInt(x, 16) : NaN)) : []);
376
+ const a = parse(halves[0]);
377
+ const b = halves.length === 2 ? parse(halves[1]) : [];
378
+ if ([...a, ...b].some((x) => Number.isNaN(x)))
379
+ return null;
380
+ const fill = halves.length === 2 ? 8 - a.length - b.length : 0;
381
+ if (fill < 0 || (halves.length === 1 && a.length !== 8))
382
+ return null;
383
+ const words = [...a, ...Array(fill).fill(0), ...b];
384
+ const bytes = [];
385
+ for (const w of words)
386
+ bytes.push(w >> 8, w & 255);
387
+ if (tail.length)
388
+ bytes.splice(12, 4, ...tail);
389
+ return bytes;
390
+ }
391
+ function v4Private(b) {
392
+ const [a, c] = b;
393
+ return a === 0 || a === 10 || a === 127 || (a === 100 && c >= 64 && c < 128) || (a === 169 && c === 254) || (a === 172 && c >= 16 && c < 32) || (a === 192 && c === 168) || (a === 198 && (c === 18 || c === 19));
394
+ }
395
+ /** Private, loopback, link-local or unique-local, IPv4-mapped/compatible decoded. */
396
+ function isPrivateAddress(addr) {
397
+ const a = addr.toLowerCase().replace(/^\[|\]$/g, '').split('%')[0];
398
+ const v4 = parseV4(a);
399
+ if (v4)
400
+ return v4Private(v4);
401
+ const v6 = parseV6(a);
402
+ if (!v6)
403
+ return false;
404
+ const zero10 = v6.slice(0, 10).every((x) => x === 0);
405
+ if (zero10 && v6[10] === 0xff && v6[11] === 0xff)
406
+ return v4Private(v6.slice(12));
407
+ const zero12 = zero10 && v6[10] === 0 && v6[11] === 0;
408
+ const loopOrAny = v6.slice(12, 15).every((x) => x === 0) && v6[15] <= 1;
409
+ if (zero12 && !loopOrAny)
410
+ return v4Private(v6.slice(12));
411
+ if (v6.every((x) => x === 0))
412
+ return true;
413
+ if (v6.slice(0, 15).every((x) => x === 0) && v6[15] === 1)
414
+ return true;
415
+ if ((v6[0] & 0xfe) === 0xfc)
416
+ return true;
417
+ if (v6[0] === 0xfe && (v6[1] & 0xc0) === 0x80)
418
+ return true;
419
+ return false;
420
+ }
421
+ function isIpLiteral(host) {
422
+ return Boolean(parseV4(host) || parseV6(host));
423
+ }
424
+ function isObfuscatedV4(host) {
425
+ if (!host || parseV4(host))
426
+ return false;
427
+ if (/^\d+$/.test(host))
428
+ return true;
429
+ if (/^0x[0-9a-f]+$/i.test(host))
430
+ return true;
431
+ const parts = host.split('.');
432
+ if (parts.length > 4 || parts.length < 2)
433
+ return false;
434
+ if (!parts.every((p) => /^(0x[0-9a-f]+|\d+)$/i.test(p)))
435
+ return false;
436
+ return parts.length < 4 || parts.some((p) => /^0\d/.test(p) || /^0x/i.test(p));
437
+ }
438
+ const DNSLOG_SUFFIXES = dnslog_domains_json_1.default.domains;
439
+ const DNSLOG_HOSTS = new Set(dnslog_domains_json_1.default.hosts);
440
+ function hostMatches(host, pattern) {
441
+ const p = pattern.toLowerCase();
442
+ if (p.startsWith('*.'))
443
+ return host.endsWith(p.slice(1)) && host.length > p.length - 1;
444
+ return host === p;
445
+ }
446
+ /** Whether an input taints the URL's host. */
447
+ function taintOf(url, host, inputs) {
448
+ const cands = inputs.filter((i) => i.value.length >= 3);
449
+ if (host) {
450
+ const hostEnd = url.toLowerCase().indexOf(host) + host.length;
451
+ return cands.find((i) => i.value.toLowerCase().includes(host) || (url.startsWith(i.value) && i.value.length >= hostEnd));
452
+ }
453
+ // No host (file:, gopher: without //): an input that is a prefix past the scheme.
454
+ const schemeEnd = url.indexOf(':') + 1;
455
+ return cands.find((i) => url.startsWith(i.value) && i.value.length > schemeEnd);
456
+ }
457
+ function detectSsrf(url, inputs, resolved = []) {
458
+ const raw = rawUrl(url);
459
+ if (!raw)
460
+ return null;
461
+ const inp = taintOf(url, raw.host, inputs);
462
+ if (!inp)
463
+ return null;
464
+ const host = raw.host;
465
+ if (SSRF_PROTOCOLS.has(raw.scheme))
466
+ return { attack: 'ssrf', rule: 'ssrf.protocol', input: inp };
467
+ if (exports.METADATA_HOSTS.includes(host) || resolved.some((a) => exports.METADATA_HOSTS.includes(a.toLowerCase())))
468
+ return { attack: 'ssrf', rule: 'ssrf.metadata', input: inp };
469
+ if (isObfuscatedV4(host))
470
+ return { attack: 'ssrf', rule: 'ssrf.obfuscated', input: inp };
471
+ if (host === 'localhost' || host.endsWith('.localhost') || (isIpLiteral(host) && isPrivateAddress(host)) || resolved.some(isPrivateAddress)) {
472
+ return { attack: 'ssrf', rule: 'ssrf.internal', input: inp };
473
+ }
474
+ if (DNSLOG_HOSTS.has(host) || DNSLOG_SUFFIXES.some((s) => host.endsWith(s)))
475
+ return { attack: 'ssrf', rule: 'ssrf.dnslog', input: inp };
476
+ (0, iast_scope_1.noteVulnerability)(() => (0, iast_rules_1.vulnSsrf)(url, raw, inputs)); // passive IAST
477
+ return null;
478
+ }
479
+ /** outbound.not_allowed: host matches none of the allow-list (always-allowed hosts aside). */
480
+ function detectOutbound(url, allow, alwaysAllowed = []) {
481
+ if (!allow.length)
482
+ return null;
483
+ const raw = rawUrl(url);
484
+ if (!raw || !raw.host)
485
+ return null;
486
+ if (alwaysAllowed.includes(raw.host) || allow.some((p) => hostMatches(raw.host, p)))
487
+ return null;
488
+ return { attack: 'outbound', rule: 'outbound.not_allowed', target: raw.host };
489
+ }
490
+ // ---- Deserialization, code, XML, XSS ------------------------------------------
491
+ /** Data is tainted when equal to an input, contained in one, or containing one of length >= 8. */
492
+ function taintedData(data, inputs) {
493
+ if (!data)
494
+ return undefined;
495
+ for (const i of inputs) {
496
+ if (!i.value)
497
+ continue;
498
+ if (i.value === data || i.value.includes(data) || (i.value.length >= 8 && data.includes(i.value)))
499
+ return i;
500
+ if (i.value.length >= 8 && /^[A-Za-z0-9+/=_-]+$/.test(i.value)) {
501
+ const dec = Buffer.from(i.value, 'base64').toString('latin1');
502
+ if (dec && (dec === data || (dec.length >= 8 && (dec.includes(data) || data.includes(dec)))))
503
+ return i;
504
+ }
505
+ }
506
+ return undefined;
507
+ }
508
+ const JSONPICKLE_MARKS = ['"py/reduce"', '"py/object"', '"py/type"', '"py/function"', '"py/repr"', '"py/newargs"'];
509
+ /** A SnakeYAML global tag naming a Java class; standard tags such as `!!str` have no dot and never match. */
510
+ const SNAKEYAML_CLASS_TAG = /(?:^|[\s[{,])(?:!!|!<tag:yaml\.org,2002:)[A-Za-z_$][A-Za-z0-9_$]*\.[A-Za-z_$]/;
511
+ function detectDeserialization(format, data, inputs) {
512
+ const inp = taintedData(data, inputs);
513
+ if (!inp)
514
+ return null;
515
+ // Passive IAST: tainted data reaching an unsafe deserializer, whatever the format check says.
516
+ (0, iast_scope_1.noteVulnerability)(() => (0, iast_rules_1.vulnData)('vuln.deser_input', data, taintedData(data, inputs.filter((i) => i.source === 'request'))));
517
+ const hit = (rule) => ({ attack: 'deserialization', rule, input: inp });
518
+ switch (format) {
519
+ case 'pickle':
520
+ return hit('deser.pickle');
521
+ case 'marshal':
522
+ return hit('deser.marshal');
523
+ case 'binaryformatter':
524
+ return hit('deser.binaryformatter');
525
+ case 'java':
526
+ return hit('deser.java');
527
+ case 'snakeyaml':
528
+ return SNAKEYAML_CLASS_TAG.test(data) ? hit('deser.yaml') : null;
529
+ case 'yaml':
530
+ return data.includes('!!python/') || data.includes('!!js/') ? hit('deser.yaml') : null;
531
+ case 'jsonpickle':
532
+ return JSONPICKLE_MARKS.some((m) => data.includes(m)) ? hit('deser.jsonpickle') : null;
533
+ case 'node_serialize':
534
+ return data.includes('_$$ND_FUNC$$_') ? hit('deser.node_serialize') : null;
535
+ case 'funcster':
536
+ return data.includes('__js_function') ? hit('deser.funcster') : null;
537
+ case 'typename':
538
+ return data.includes('"$type"') || data.includes('"__type"') ? hit('deser.typename') : null;
539
+ }
540
+ return null;
541
+ }
542
+ function detectCode(code, inputs) {
543
+ if (!code)
544
+ return null;
545
+ let tokens = null;
546
+ for (const inp of inputs) {
547
+ if (inp.value.length < 3)
548
+ continue;
549
+ if (inp.value === code)
550
+ return { attack: 'code_injection', rule: 'code.eval', input: inp };
551
+ for (const idx of (0, lexers_1.occurrences)(code, inp.value)) {
552
+ tokens ?? (tokens = (0, lexers_1.codeTokens)(code));
553
+ if ((0, lexers_1.overlapping)(tokens, idx, inp.value.length).length >= 2)
554
+ return { attack: 'code_injection', rule: 'code.eval', input: inp };
555
+ }
556
+ }
557
+ (0, iast_scope_1.noteVulnerability)(() => (0, iast_rules_1.vulnCode)(code, inputs, () => (tokens ?? (tokens = (0, lexers_1.codeTokens)(code))))); // passive IAST
558
+ return null;
559
+ }
560
+ const INCLUDE_PATHLIKE = /[/\\]|\.\./;
561
+ const INCLUDE_ABSOLUTE = /^(?:\/|[A-Za-z]:[\\/]|\\\\|file:)/i;
562
+ /** code.include: a module specifier that is, or carries a path from, an input. */
563
+ function detectInclude(specifier, inputs) {
564
+ if (typeof specifier !== 'string' || !specifier)
565
+ return null;
566
+ for (const inp of inputs) {
567
+ if (!inp.value)
568
+ continue;
569
+ if (inp.value === specifier)
570
+ return { attack: 'code_injection', rule: 'code.include', input: inp };
571
+ if (inp.value.length >= 3 && specifier.includes(inp.value) && (INCLUDE_ABSOLUTE.test(inp.value) || INCLUDE_PATHLIKE.test(inp.value) || inp.value.includes('\0'))) {
572
+ return { attack: 'code_injection', rule: 'code.include', input: inp };
573
+ }
574
+ }
575
+ (0, iast_scope_1.noteVulnerability)(() => (0, iast_rules_1.vulnInclude)(specifier, inputs)); // passive IAST
576
+ return null;
577
+ }
578
+ /** file_write.upload: an uploaded file whose name is a script (README "Path"). */
579
+ function detectUpload(input) {
580
+ const name = input.value.split(/[\\/]/).pop() || '';
581
+ return exports.SCRIPT_FILE.test(name) ? { attack: 'file_write', rule: 'file_write.upload', input } : null;
582
+ }
583
+ /** Reads the DOCTYPE: external DTD id and entity declarations. */
584
+ function parseDoctype(xml) {
585
+ const at = xml.indexOf('<!DOCTYPE');
586
+ if (at < 0)
587
+ return { hasDoctype: false, externalDtd: null, entities: [] };
588
+ const head = xml.slice(at, at + 64 * 1024);
589
+ const bracket = head.indexOf('[');
590
+ const close = head.indexOf('>');
591
+ const decl = head.slice(0, bracket >= 0 && bracket < close ? bracket : close);
592
+ const ext = /\s(SYSTEM|PUBLIC)\s/.exec(decl);
593
+ let externalDtd = null;
594
+ if (ext) {
595
+ const lits = decl.slice(ext.index).match(/"[^"]*"|'[^']*'/g) || [];
596
+ externalDtd = (lits[ext[1] === 'PUBLIC' ? 1 : 0] || lits[0] || '').slice(1, -1);
597
+ }
598
+ const entities = [];
599
+ let from = 0;
600
+ while (entities.length < 1000) {
601
+ const i = head.indexOf('<!ENTITY', from);
602
+ if (i < 0)
603
+ break;
604
+ const end = head.indexOf('>', i);
605
+ const body = head.slice(i + 8, end < 0 ? undefined : end).trim();
606
+ from = end < 0 ? head.length : end + 1;
607
+ const m = /^(%\s+)?([^\s]+)\s+(.*)$/s.exec(body);
608
+ if (!m)
609
+ continue;
610
+ const rest = m[3].trim();
611
+ const lits = rest.match(/"[^"]*"|'[^']*'/g) || [];
612
+ const external = /^(SYSTEM|PUBLIC)\b/.test(rest);
613
+ const uri = external ? (lits[rest.startsWith('PUBLIC') ? 1 : 0] || '').slice(1, -1) : '';
614
+ entities.push({ name: m[2], external, uri, value: external ? '' : (lits[0] || '').slice(1, -1) });
615
+ }
616
+ return { hasDoctype: true, externalDtd, entities };
617
+ }
618
+ const XXE_PROTOCOLS = new Set('ftp dict gopher netdoc mailto jar php expect'.split(' '));
619
+ function detectXml(xml, inputs, resolvesExternal) {
620
+ // Passive IAST: request data parsed by a parser that resolves external entities, DOCTYPE or not.
621
+ if (xml && resolvesExternal)
622
+ (0, iast_scope_1.noteVulnerability)(() => (0, iast_rules_1.vulnData)('vuln.xml_external', xml, taintedData(xml, inputs.filter((i) => i.source === 'request'))));
623
+ if (!xml || !xml.includes('<!DOCTYPE'))
624
+ return null;
625
+ const inp = taintedData(xml, inputs);
626
+ if (!inp)
627
+ return null;
628
+ const d = parseDoctype(xml);
629
+ const uris = d.entities.filter((e) => e.external).map((e) => e.uri);
630
+ if (d.externalDtd !== null)
631
+ uris.push(d.externalDtd);
632
+ for (const u of uris) {
633
+ const scheme = /^([a-z][a-z0-9+.-]*):/i.exec(u)?.[1]?.toLowerCase();
634
+ if ((scheme && XXE_PROTOCOLS.has(scheme)) || u.startsWith('\\\\'))
635
+ return { attack: 'xxe', rule: 'xxe.protocol', input: inp };
636
+ if (scheme === 'file') {
637
+ const p = u.replace(/^file:(\/\/)?/i, '');
638
+ if ((p.startsWith('/') || /^[A-Za-z]:/.test(p) || p.includes('../')) && !/\.(dtd|xsd|xml)$/i.test(p))
639
+ return { attack: 'xxe', rule: 'xxe.file', input: inp };
640
+ }
641
+ }
642
+ if (uris.length)
643
+ return { attack: 'xxe', rule: resolvesExternal ? 'xxe.external_entity' : 'xxe.doctype', input: inp };
644
+ const referencing = d.entities.filter((e) => !e.external && /[&%][^\s;]+;/.test(e.value));
645
+ if (referencing.length >= 3)
646
+ return { attack: 'xxe', rule: 'xxe.billion_laughs', input: inp };
647
+ return null;
648
+ }
649
+ // The contract's tag pattern (OpenRASP xss_userinput) includes control characters on purpose.
650
+ // eslint-disable-next-line no-control-regex
651
+ const XSS_TAG = /<![-[A-Za-z]|<([A-Za-z]{1,12})[/>\x00-\x20]/;
652
+ const XSS_HANDLER = /\bon[a-z]{3,}\s*=/i;
653
+ exports.MAX_XSS_BODY = 1024 * 1024;
654
+ function detectXss(contentType, body, inputs) {
655
+ if (!contentType || !contentType.toLowerCase().includes('html') || !body || body.length > exports.MAX_XSS_BODY)
656
+ return null;
657
+ for (const inp of inputs) {
658
+ const v = inp.value;
659
+ if (v.length < 15)
660
+ continue;
661
+ if (!(XSS_TAG.test(v) || v.toLowerCase().includes('javascript:') || XSS_HANDLER.test(v)))
662
+ continue;
663
+ if (body.includes(v))
664
+ return { attack: 'xss', rule: 'xss.reflected', input: inp };
665
+ }
666
+ return null;
667
+ }
668
+ // SHIELD: template-source detector uses the same code_injection attack mode.
669
+ var template_1 = require("./template");
670
+ Object.defineProperty(exports, "detectTemplate", { enumerable: true, get: function () { return template_1.detectTemplate; } });
671
+ //# sourceMappingURL=detect.js.map