shieldcortex 4.31.1 → 4.32.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 (346) hide show
  1. package/README.md +78 -2
  2. package/dashboard/.next/standalone/dashboard/.next/BUILD_ID +1 -1
  3. package/dashboard/.next/standalone/dashboard/.next/build-manifest.json +2 -2
  4. package/dashboard/.next/standalone/dashboard/.next/prerender-manifest.json +3 -3
  5. package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.html +2 -2
  6. package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.rsc +1 -1
  7. package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  8. package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  9. package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  10. package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  11. package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  12. package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.html +2 -2
  13. package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.rsc +1 -1
  14. package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  15. package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  16. package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  17. package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  18. package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  19. package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  20. package/dashboard/.next/standalone/dashboard/.next/server/app/admin.html +1 -1
  21. package/dashboard/.next/standalone/dashboard/.next/server/app/admin.rsc +1 -1
  22. package/dashboard/.next/standalone/dashboard/.next/server/app/admin.segments/!KGRhc2hib2FyZCk/admin/__PAGE__.segment.rsc +1 -1
  23. package/dashboard/.next/standalone/dashboard/.next/server/app/admin.segments/!KGRhc2hib2FyZCk/admin.segment.rsc +1 -1
  24. package/dashboard/.next/standalone/dashboard/.next/server/app/admin.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  25. package/dashboard/.next/standalone/dashboard/.next/server/app/admin.segments/_full.segment.rsc +1 -1
  26. package/dashboard/.next/standalone/dashboard/.next/server/app/admin.segments/_head.segment.rsc +1 -1
  27. package/dashboard/.next/standalone/dashboard/.next/server/app/admin.segments/_index.segment.rsc +1 -1
  28. package/dashboard/.next/standalone/dashboard/.next/server/app/admin.segments/_tree.segment.rsc +1 -1
  29. package/dashboard/.next/standalone/dashboard/.next/server/app/cloud.html +1 -1
  30. package/dashboard/.next/standalone/dashboard/.next/server/app/cloud.rsc +1 -1
  31. package/dashboard/.next/standalone/dashboard/.next/server/app/cloud.segments/!KGRhc2hib2FyZCk/cloud/__PAGE__.segment.rsc +1 -1
  32. package/dashboard/.next/standalone/dashboard/.next/server/app/cloud.segments/!KGRhc2hib2FyZCk/cloud.segment.rsc +1 -1
  33. package/dashboard/.next/standalone/dashboard/.next/server/app/cloud.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  34. package/dashboard/.next/standalone/dashboard/.next/server/app/cloud.segments/_full.segment.rsc +1 -1
  35. package/dashboard/.next/standalone/dashboard/.next/server/app/cloud.segments/_head.segment.rsc +1 -1
  36. package/dashboard/.next/standalone/dashboard/.next/server/app/cloud.segments/_index.segment.rsc +1 -1
  37. package/dashboard/.next/standalone/dashboard/.next/server/app/cloud.segments/_tree.segment.rsc +1 -1
  38. package/dashboard/.next/standalone/dashboard/.next/server/app/index.html +1 -1
  39. package/dashboard/.next/standalone/dashboard/.next/server/app/index.rsc +1 -1
  40. package/dashboard/.next/standalone/dashboard/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  41. package/dashboard/.next/standalone/dashboard/.next/server/app/index.segments/_full.segment.rsc +1 -1
  42. package/dashboard/.next/standalone/dashboard/.next/server/app/index.segments/_head.segment.rsc +1 -1
  43. package/dashboard/.next/standalone/dashboard/.next/server/app/index.segments/_index.segment.rsc +1 -1
  44. package/dashboard/.next/standalone/dashboard/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  45. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/capture.html +1 -1
  46. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/capture.rsc +1 -1
  47. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/capture.segments/!KGRhc2hib2FyZCk/memory/capture/__PAGE__.segment.rsc +1 -1
  48. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/capture.segments/!KGRhc2hib2FyZCk/memory/capture.segment.rsc +1 -1
  49. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/capture.segments/!KGRhc2hib2FyZCk/memory.segment.rsc +1 -1
  50. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/capture.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  51. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/capture.segments/_full.segment.rsc +1 -1
  52. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/capture.segments/_head.segment.rsc +1 -1
  53. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/capture.segments/_index.segment.rsc +1 -1
  54. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/capture.segments/_tree.segment.rsc +1 -1
  55. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/graph.html +1 -1
  56. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/graph.rsc +1 -1
  57. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/graph.segments/!KGRhc2hib2FyZCk/memory/graph/__PAGE__.segment.rsc +1 -1
  58. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/graph.segments/!KGRhc2hib2FyZCk/memory/graph.segment.rsc +1 -1
  59. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/graph.segments/!KGRhc2hib2FyZCk/memory.segment.rsc +1 -1
  60. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/graph.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  61. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/graph.segments/_full.segment.rsc +1 -1
  62. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/graph.segments/_head.segment.rsc +1 -1
  63. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/graph.segments/_index.segment.rsc +1 -1
  64. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/graph.segments/_tree.segment.rsc +1 -1
  65. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/recall.html +1 -1
  66. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/recall.rsc +1 -1
  67. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/recall.segments/!KGRhc2hib2FyZCk/memory/recall/__PAGE__.segment.rsc +1 -1
  68. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/recall.segments/!KGRhc2hib2FyZCk/memory/recall.segment.rsc +1 -1
  69. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/recall.segments/!KGRhc2hib2FyZCk/memory.segment.rsc +1 -1
  70. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/recall.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  71. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/recall.segments/_full.segment.rsc +1 -1
  72. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/recall.segments/_head.segment.rsc +1 -1
  73. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/recall.segments/_index.segment.rsc +1 -1
  74. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/recall.segments/_tree.segment.rsc +1 -1
  75. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/replay.html +2 -2
  76. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/replay.rsc +1 -1
  77. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/replay.segments/!KGRhc2hib2FyZCk/memory/replay/__PAGE__.segment.rsc +1 -1
  78. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/replay.segments/!KGRhc2hib2FyZCk/memory/replay.segment.rsc +1 -1
  79. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/replay.segments/!KGRhc2hib2FyZCk/memory.segment.rsc +1 -1
  80. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/replay.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  81. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/replay.segments/_full.segment.rsc +1 -1
  82. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/replay.segments/_head.segment.rsc +1 -1
  83. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/replay.segments/_index.segment.rsc +1 -1
  84. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/replay.segments/_tree.segment.rsc +1 -1
  85. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/review.html +1 -1
  86. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/review.rsc +1 -1
  87. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/review.segments/!KGRhc2hib2FyZCk/memory/review/__PAGE__.segment.rsc +1 -1
  88. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/review.segments/!KGRhc2hib2FyZCk/memory/review.segment.rsc +1 -1
  89. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/review.segments/!KGRhc2hib2FyZCk/memory.segment.rsc +1 -1
  90. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/review.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  91. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/review.segments/_full.segment.rsc +1 -1
  92. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/review.segments/_head.segment.rsc +1 -1
  93. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/review.segments/_index.segment.rsc +1 -1
  94. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/review.segments/_tree.segment.rsc +1 -1
  95. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/timeline.html +1 -1
  96. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/timeline.rsc +1 -1
  97. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/timeline.segments/!KGRhc2hib2FyZCk/memory/timeline/__PAGE__.segment.rsc +1 -1
  98. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/timeline.segments/!KGRhc2hib2FyZCk/memory/timeline.segment.rsc +1 -1
  99. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/timeline.segments/!KGRhc2hib2FyZCk/memory.segment.rsc +1 -1
  100. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/timeline.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  101. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/timeline.segments/_full.segment.rsc +1 -1
  102. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/timeline.segments/_head.segment.rsc +1 -1
  103. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/timeline.segments/_index.segment.rsc +1 -1
  104. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/timeline.segments/_tree.segment.rsc +1 -1
  105. package/dashboard/.next/standalone/dashboard/.next/server/app/memory.html +2 -2
  106. package/dashboard/.next/standalone/dashboard/.next/server/app/memory.rsc +1 -1
  107. package/dashboard/.next/standalone/dashboard/.next/server/app/memory.segments/!KGRhc2hib2FyZCk/memory/__PAGE__.segment.rsc +1 -1
  108. package/dashboard/.next/standalone/dashboard/.next/server/app/memory.segments/!KGRhc2hib2FyZCk/memory.segment.rsc +1 -1
  109. package/dashboard/.next/standalone/dashboard/.next/server/app/memory.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  110. package/dashboard/.next/standalone/dashboard/.next/server/app/memory.segments/_full.segment.rsc +1 -1
  111. package/dashboard/.next/standalone/dashboard/.next/server/app/memory.segments/_head.segment.rsc +1 -1
  112. package/dashboard/.next/standalone/dashboard/.next/server/app/memory.segments/_index.segment.rsc +1 -1
  113. package/dashboard/.next/standalone/dashboard/.next/server/app/memory.segments/_tree.segment.rsc +1 -1
  114. package/dashboard/.next/standalone/dashboard/.next/server/app/overview.html +2 -2
  115. package/dashboard/.next/standalone/dashboard/.next/server/app/overview.rsc +1 -1
  116. package/dashboard/.next/standalone/dashboard/.next/server/app/overview.segments/!KGRhc2hib2FyZCk/overview/__PAGE__.segment.rsc +1 -1
  117. package/dashboard/.next/standalone/dashboard/.next/server/app/overview.segments/!KGRhc2hib2FyZCk/overview.segment.rsc +1 -1
  118. package/dashboard/.next/standalone/dashboard/.next/server/app/overview.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  119. package/dashboard/.next/standalone/dashboard/.next/server/app/overview.segments/_full.segment.rsc +1 -1
  120. package/dashboard/.next/standalone/dashboard/.next/server/app/overview.segments/_head.segment.rsc +1 -1
  121. package/dashboard/.next/standalone/dashboard/.next/server/app/overview.segments/_index.segment.rsc +1 -1
  122. package/dashboard/.next/standalone/dashboard/.next/server/app/overview.segments/_tree.segment.rsc +1 -1
  123. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/audit.html +1 -1
  124. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/audit.rsc +1 -1
  125. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/audit.segments/!KGRhc2hib2FyZCk/protection/audit/__PAGE__.segment.rsc +1 -1
  126. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/audit.segments/!KGRhc2hib2FyZCk/protection/audit.segment.rsc +1 -1
  127. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/audit.segments/!KGRhc2hib2FyZCk/protection.segment.rsc +1 -1
  128. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/audit.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  129. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/audit.segments/_full.segment.rsc +1 -1
  130. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/audit.segments/_head.segment.rsc +1 -1
  131. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/audit.segments/_index.segment.rsc +1 -1
  132. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/audit.segments/_tree.segment.rsc +1 -1
  133. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/intercepts.html +1 -1
  134. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/intercepts.rsc +1 -1
  135. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/intercepts.segments/!KGRhc2hib2FyZCk/protection/intercepts/__PAGE__.segment.rsc +1 -1
  136. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/intercepts.segments/!KGRhc2hib2FyZCk/protection/intercepts.segment.rsc +1 -1
  137. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/intercepts.segments/!KGRhc2hib2FyZCk/protection.segment.rsc +1 -1
  138. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/intercepts.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  139. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/intercepts.segments/_full.segment.rsc +1 -1
  140. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/intercepts.segments/_head.segment.rsc +1 -1
  141. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/intercepts.segments/_index.segment.rsc +1 -1
  142. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/intercepts.segments/_tree.segment.rsc +1 -1
  143. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/iron-dome.html +1 -1
  144. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/iron-dome.rsc +1 -1
  145. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/iron-dome.segments/!KGRhc2hib2FyZCk/protection/iron-dome/__PAGE__.segment.rsc +1 -1
  146. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/iron-dome.segments/!KGRhc2hib2FyZCk/protection/iron-dome.segment.rsc +1 -1
  147. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/iron-dome.segments/!KGRhc2hib2FyZCk/protection.segment.rsc +1 -1
  148. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/iron-dome.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  149. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/iron-dome.segments/_full.segment.rsc +1 -1
  150. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/iron-dome.segments/_head.segment.rsc +1 -1
  151. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/iron-dome.segments/_index.segment.rsc +1 -1
  152. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/iron-dome.segments/_tree.segment.rsc +1 -1
  153. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/policies.html +1 -1
  154. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/policies.rsc +1 -1
  155. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/policies.segments/!KGRhc2hib2FyZCk/protection/policies/__PAGE__.segment.rsc +1 -1
  156. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/policies.segments/!KGRhc2hib2FyZCk/protection/policies.segment.rsc +1 -1
  157. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/policies.segments/!KGRhc2hib2FyZCk/protection.segment.rsc +1 -1
  158. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/policies.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  159. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/policies.segments/_full.segment.rsc +1 -1
  160. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/policies.segments/_head.segment.rsc +1 -1
  161. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/policies.segments/_index.segment.rsc +1 -1
  162. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/policies.segments/_tree.segment.rsc +1 -1
  163. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/quarantine.html +1 -1
  164. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/quarantine.rsc +1 -1
  165. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/quarantine.segments/!KGRhc2hib2FyZCk/protection/quarantine/__PAGE__.segment.rsc +1 -1
  166. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/quarantine.segments/!KGRhc2hib2FyZCk/protection/quarantine.segment.rsc +1 -1
  167. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/quarantine.segments/!KGRhc2hib2FyZCk/protection.segment.rsc +1 -1
  168. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/quarantine.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  169. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/quarantine.segments/_full.segment.rsc +1 -1
  170. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/quarantine.segments/_head.segment.rsc +1 -1
  171. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/quarantine.segments/_index.segment.rsc +1 -1
  172. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/quarantine.segments/_tree.segment.rsc +1 -1
  173. package/dashboard/.next/standalone/dashboard/.next/server/app/protection.html +2 -2
  174. package/dashboard/.next/standalone/dashboard/.next/server/app/protection.rsc +1 -1
  175. package/dashboard/.next/standalone/dashboard/.next/server/app/protection.segments/!KGRhc2hib2FyZCk/protection/__PAGE__.segment.rsc +1 -1
  176. package/dashboard/.next/standalone/dashboard/.next/server/app/protection.segments/!KGRhc2hib2FyZCk/protection.segment.rsc +1 -1
  177. package/dashboard/.next/standalone/dashboard/.next/server/app/protection.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  178. package/dashboard/.next/standalone/dashboard/.next/server/app/protection.segments/_full.segment.rsc +1 -1
  179. package/dashboard/.next/standalone/dashboard/.next/server/app/protection.segments/_head.segment.rsc +1 -1
  180. package/dashboard/.next/standalone/dashboard/.next/server/app/protection.segments/_index.segment.rsc +1 -1
  181. package/dashboard/.next/standalone/dashboard/.next/server/app/protection.segments/_tree.segment.rsc +1 -1
  182. package/dashboard/.next/standalone/dashboard/.next/server/app/settings.html +2 -2
  183. package/dashboard/.next/standalone/dashboard/.next/server/app/settings.rsc +1 -1
  184. package/dashboard/.next/standalone/dashboard/.next/server/app/settings.segments/!KGRhc2hib2FyZCk/settings/__PAGE__.segment.rsc +1 -1
  185. package/dashboard/.next/standalone/dashboard/.next/server/app/settings.segments/!KGRhc2hib2FyZCk/settings.segment.rsc +1 -1
  186. package/dashboard/.next/standalone/dashboard/.next/server/app/settings.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  187. package/dashboard/.next/standalone/dashboard/.next/server/app/settings.segments/_full.segment.rsc +1 -1
  188. package/dashboard/.next/standalone/dashboard/.next/server/app/settings.segments/_head.segment.rsc +1 -1
  189. package/dashboard/.next/standalone/dashboard/.next/server/app/settings.segments/_index.segment.rsc +1 -1
  190. package/dashboard/.next/standalone/dashboard/.next/server/app/settings.segments/_tree.segment.rsc +1 -1
  191. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain/xray.html +1 -1
  192. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain/xray.rsc +1 -1
  193. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain/xray.segments/!KGRhc2hib2FyZCk/supply-chain/xray/__PAGE__.segment.rsc +1 -1
  194. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain/xray.segments/!KGRhc2hib2FyZCk/supply-chain/xray.segment.rsc +1 -1
  195. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain/xray.segments/!KGRhc2hib2FyZCk/supply-chain.segment.rsc +1 -1
  196. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain/xray.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  197. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain/xray.segments/_full.segment.rsc +1 -1
  198. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain/xray.segments/_head.segment.rsc +1 -1
  199. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain/xray.segments/_index.segment.rsc +1 -1
  200. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain/xray.segments/_tree.segment.rsc +1 -1
  201. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain.html +1 -1
  202. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain.rsc +1 -1
  203. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain.segments/!KGRhc2hib2FyZCk/supply-chain/__PAGE__.segment.rsc +1 -1
  204. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain.segments/!KGRhc2hib2FyZCk/supply-chain.segment.rsc +1 -1
  205. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  206. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain.segments/_full.segment.rsc +1 -1
  207. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain.segments/_head.segment.rsc +1 -1
  208. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain.segments/_index.segment.rsc +1 -1
  209. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain.segments/_tree.segment.rsc +1 -1
  210. package/dashboard/.next/standalone/dashboard/.next/server/app/xray.html +2 -2
  211. package/dashboard/.next/standalone/dashboard/.next/server/app/xray.rsc +1 -1
  212. package/dashboard/.next/standalone/dashboard/.next/server/app/xray.segments/!KGRhc2hib2FyZCk/xray/__PAGE__.segment.rsc +1 -1
  213. package/dashboard/.next/standalone/dashboard/.next/server/app/xray.segments/!KGRhc2hib2FyZCk/xray.segment.rsc +1 -1
  214. package/dashboard/.next/standalone/dashboard/.next/server/app/xray.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  215. package/dashboard/.next/standalone/dashboard/.next/server/app/xray.segments/_full.segment.rsc +1 -1
  216. package/dashboard/.next/standalone/dashboard/.next/server/app/xray.segments/_head.segment.rsc +1 -1
  217. package/dashboard/.next/standalone/dashboard/.next/server/app/xray.segments/_index.segment.rsc +1 -1
  218. package/dashboard/.next/standalone/dashboard/.next/server/app/xray.segments/_tree.segment.rsc +1 -1
  219. package/dashboard/.next/standalone/dashboard/.next/server/pages/404.html +2 -2
  220. package/dashboard/.next/standalone/dashboard/.next/server/pages/500.html +2 -2
  221. package/dashboard/.next/standalone/dashboard/.next/server/server-reference-manifest.js +1 -1
  222. package/dashboard/.next/standalone/dashboard/.next/server/server-reference-manifest.json +1 -1
  223. package/dist/api/control.d.ts +2 -0
  224. package/dist/api/control.js +119 -2
  225. package/dist/api/routes/memories.js +19 -14
  226. package/dist/api/routes/system.js +2 -3
  227. package/dist/api/visualization-server.d.ts +13 -1
  228. package/dist/api/visualization-server.js +57 -1
  229. package/dist/audit/env-scanner.js +5 -2
  230. package/dist/audit/index.d.ts +4 -1
  231. package/dist/audit/index.js +2 -1
  232. package/dist/audit/mcp-config-scanner.d.ts +23 -0
  233. package/dist/audit/mcp-config-scanner.js +110 -0
  234. package/dist/audit/mcp-tools-scanner.d.ts +112 -0
  235. package/dist/audit/mcp-tools-scanner.js +299 -0
  236. package/dist/cli/audit.d.ts +1 -0
  237. package/dist/cli/audit.js +12 -1
  238. package/dist/cli/mcp.d.ts +13 -0
  239. package/dist/cli/mcp.js +0 -0
  240. package/dist/cli/remember.d.ts +75 -0
  241. package/dist/cli/remember.js +195 -0
  242. package/dist/cloud/config.d.ts +23 -1
  243. package/dist/cloud/config.js +453 -193
  244. package/dist/cloud/quarantine-sync.d.ts +12 -2
  245. package/dist/cloud/quarantine-sync.js +28 -6
  246. package/dist/cloud/sync-queue.d.ts +21 -2
  247. package/dist/cloud/sync-queue.js +124 -29
  248. package/dist/database/better-sqlite3-guard.d.ts +27 -2
  249. package/dist/database/better-sqlite3-guard.js +58 -5
  250. package/dist/database/init.js +85 -17
  251. package/dist/database/inline-schema.js +35 -1
  252. package/dist/database/migrations.js +104 -8
  253. package/dist/database/schema.sql +39 -1
  254. package/dist/defence/audit/queries.d.ts +10 -2
  255. package/dist/defence/audit/queries.js +30 -4
  256. package/dist/defence/audit/retention.d.ts +50 -0
  257. package/dist/defence/audit/retention.js +161 -0
  258. package/dist/defence/credential-leak/entropy.d.ts +11 -0
  259. package/dist/defence/credential-leak/entropy.js +27 -0
  260. package/dist/defence/credential-leak/index.js +27 -1
  261. package/dist/defence/credential-leak/patterns.d.ts +9 -0
  262. package/dist/defence/credential-leak/patterns.js +21 -0
  263. package/dist/defence/custom-patterns/store.js +8 -1
  264. package/dist/defence/custom-rules/store.d.ts +18 -0
  265. package/dist/defence/custom-rules/store.js +63 -0
  266. package/dist/defence/firewall/confusables.d.ts +30 -0
  267. package/dist/defence/firewall/confusables.js +87 -0
  268. package/dist/defence/firewall/encoding-detector.js +23 -9
  269. package/dist/defence/firewall/index.d.ts +11 -1
  270. package/dist/defence/firewall/index.js +34 -1
  271. package/dist/defence/firewall/instruction-detector.js +18 -7
  272. package/dist/defence/firewall/markdown-image-detector.d.ts +34 -0
  273. package/dist/defence/firewall/markdown-image-detector.js +83 -0
  274. package/dist/defence/fragmentation/entity-extractor.js +17 -6
  275. package/dist/defence/index.d.ts +5 -0
  276. package/dist/defence/index.js +8 -0
  277. package/dist/defence/iron-dome/index.js +7 -1
  278. package/dist/defence/pipeline.js +62 -10
  279. package/dist/defence/scan-windows.d.ts +41 -0
  280. package/dist/defence/scan-windows.js +61 -0
  281. package/dist/defence/semantic/attack-corpus.d.ts +22 -0
  282. package/dist/defence/semantic/attack-corpus.js +75 -0
  283. package/dist/defence/semantic/index.d.ts +67 -0
  284. package/dist/defence/semantic/index.js +138 -0
  285. package/dist/defence/skill-scanner/deep-scan.js +35 -15
  286. package/dist/defence/skill-scanner/patterns.d.ts +1 -1
  287. package/dist/defence/skill-scanner/patterns.js +8 -7
  288. package/dist/defence/tool-response-scanner.d.ts +21 -5
  289. package/dist/defence/tool-response-scanner.js +111 -22
  290. package/dist/defence/types.d.ts +11 -1
  291. package/dist/index.d.ts +29 -0
  292. package/dist/index.js +104 -20
  293. package/dist/memory/consolidate.js +1 -1
  294. package/dist/memory/decay.js +3 -1
  295. package/dist/memory/embedding.d.ts +18 -2
  296. package/dist/memory/embedding.js +32 -11
  297. package/dist/memory/expiry.js +1 -1
  298. package/dist/memory/search-recall.js +107 -49
  299. package/dist/memory/search.d.ts +19 -3
  300. package/dist/memory/search.js +25 -10
  301. package/dist/memory/store.d.ts +13 -2
  302. package/dist/memory/store.js +115 -11
  303. package/dist/scan-only.d.ts +64 -0
  304. package/dist/scan-only.js +173 -0
  305. package/dist/server.d.ts +5 -0
  306. package/dist/server.js +6 -4
  307. package/dist/setup/claude-md.js +39 -34
  308. package/dist/setup/codex.js +9 -2
  309. package/dist/setup/copilot.js +160 -47
  310. package/dist/setup/json-config.d.ts +99 -0
  311. package/dist/setup/json-config.js +167 -0
  312. package/dist/setup/migrate.js +1 -1
  313. package/dist/setup/settings-hooks.js +8 -13
  314. package/dist/setup/uninstall.js +1 -21
  315. package/dist/tools/context.d.ts +8 -8
  316. package/dist/tools/forget.d.ts +9 -8
  317. package/dist/tools/forget.js +17 -4
  318. package/dist/tools/recall.d.ts +13 -13
  319. package/dist/tools/remember.d.ts +16 -16
  320. package/dist/tools/remember.js +19 -8
  321. package/dist/worker/brain-worker.d.ts +1 -0
  322. package/dist/worker/brain-worker.js +79 -16
  323. package/dist/worker/types.d.ts +8 -0
  324. package/dist/worker/types.js +8 -0
  325. package/dist/xray/dir-scanner.d.ts +18 -0
  326. package/dist/xray/dir-scanner.js +23 -1
  327. package/dist/xray/file-scanner.js +16 -1
  328. package/dist/xray/findings-store.js +9 -1
  329. package/dist/xray/index.d.ts +2 -0
  330. package/dist/xray/index.js +10 -1
  331. package/dist/xray/npm-inspector.d.ts +31 -0
  332. package/dist/xray/npm-inspector.js +135 -29
  333. package/dist/xray/patterns.d.ts +1 -1
  334. package/dist/xray/patterns.js +20 -23
  335. package/dist/xray/sarif.d.ts +78 -0
  336. package/dist/xray/sarif.js +166 -0
  337. package/dist/xray/watch.d.ts +1 -0
  338. package/dist/xray/watch.js +10 -1
  339. package/hooks/openclaw/cortex-memory/handler.ts +122 -18
  340. package/hooks/openclaw/cortex-memory/runtime.mjs +10 -4
  341. package/package.json +10 -3
  342. package/dist/memory/embedding-cache.d.ts +0 -20
  343. package/dist/memory/embedding-cache.js +0 -91
  344. /package/dashboard/.next/standalone/dashboard/.next/static/{T0hqc-Le01c8QVY0VrHnu → Ox9scglBehbbCk7DD8-Vn}/_buildManifest.js +0 -0
  345. /package/dashboard/.next/standalone/dashboard/.next/static/{T0hqc-Le01c8QVY0VrHnu → Ox9scglBehbbCk7DD8-Vn}/_clientMiddlewareManifest.json +0 -0
  346. /package/dashboard/.next/standalone/dashboard/.next/static/{T0hqc-Le01c8QVY0VrHnu → Ox9scglBehbbCk7DD8-Vn}/_ssgManifest.js +0 -0
@@ -246,9 +246,16 @@ export async function scanFile(filePath, deep) {
246
246
  if (!stat.isFile() || stat.size > MAX_FILE_SIZE) {
247
247
  return findings;
248
248
  }
249
+ // Read the file body AT MOST ONCE. Each branch records what it read so deep
250
+ // mode (below) can reuse it instead of re-reading from disk. Previously a
251
+ // deep scan read every file a second time (and on every other-text file,
252
+ // walked the same content twice) — pure wasted IO for large trees.
253
+ let fileBuffer = null;
254
+ let textContent = null;
249
255
  // Route by extension
250
256
  if (IMAGE_EXTENSIONS.has(ext)) {
251
257
  const buf = fs.readFileSync(filePath);
258
+ fileBuffer = buf;
252
259
  findings.push(...scanImage(filePath, buf));
253
260
  // Polyglot check
254
261
  const polyglot = checkPolyglot(buf);
@@ -259,6 +266,7 @@ export async function scanFile(filePath, deep) {
259
266
  }
260
267
  else if (JSON_EXTENSIONS.has(ext)) {
261
268
  const content = fs.readFileSync(filePath, 'utf-8');
269
+ textContent = content;
262
270
  findings.push(...scanJson(filePath, content));
263
271
  // Zero-width unicode check
264
272
  const zw = hasZeroWidthUnicode(content);
@@ -269,6 +277,7 @@ export async function scanFile(filePath, deep) {
269
277
  }
270
278
  else if (CODE_EXTENSIONS.has(ext)) {
271
279
  const content = fs.readFileSync(filePath, 'utf-8');
280
+ textContent = content;
272
281
  findings.push(...detectPatterns(content, filePath));
273
282
  // Zero-width unicode check
274
283
  const zw = hasZeroWidthUnicode(content);
@@ -281,6 +290,7 @@ export async function scanFile(filePath, deep) {
281
290
  // For any other text-like file, try reading as text
282
291
  try {
283
292
  const buf = fs.readFileSync(filePath);
293
+ fileBuffer = buf;
284
294
  // Check if it's mostly text
285
295
  let nonPrintable = 0;
286
296
  const sampleSize = Math.min(buf.length, 8192);
@@ -293,6 +303,7 @@ export async function scanFile(filePath, deep) {
293
303
  if (nonPrintable / sampleSize < 0.1) {
294
304
  // Treat as text
295
305
  const content = buf.toString('utf-8');
306
+ textContent = content;
296
307
  findings.push(...detectPatterns(content, filePath));
297
308
  const zw = hasZeroWidthUnicode(content);
298
309
  if (zw) {
@@ -316,7 +327,11 @@ export async function scanFile(filePath, deep) {
316
327
  // Deep mode: additional analysis (Pro feature)
317
328
  if (deep && stat.size > 0) {
318
329
  try {
319
- const content = fs.readFileSync(filePath, 'utf-8');
330
+ // Reuse the content already read above. Derive text from a buffer the
331
+ // image/binary branch read (no re-read); only hit disk if nothing was
332
+ // captured (a branch that didn't read, e.g. an early-skipped path).
333
+ const content = textContent ??
334
+ (fileBuffer ? fileBuffer.toString('utf-8') : fs.readFileSync(filePath, 'utf-8'));
320
335
  // Entropy analysis — detect packed/obfuscated code
321
336
  if (CODE_EXTENSIONS.has(ext) || ext === '.js' || ext === '.mjs') {
322
337
  const entropy = shannonEntropy(content);
@@ -43,7 +43,15 @@ export function createFindingsStore(basePath) {
43
43
  addFindings(sourceId, sourceKind, target, rawFindings) {
44
44
  const now = new Date().toISOString();
45
45
  const existing = readFindings();
46
- const existingKeys = new Set(existing.filter((f) => f.status === 'new').map((f) => findingDedupeKey(f.target, f)));
46
+ // Dedupe against EVERY retained finding regardless of status (Phase 17
47
+ // B5). Previously only `status === 'new'` findings seeded the dedupe set,
48
+ // so a finding the user had already triaged — ignored, resolved,
49
+ // reviewed or quarantined — resurfaced as a brand-new duplicate on every
50
+ // re-scan, undoing their decision. Matching across all statuses respects
51
+ // the prior triage. (Findings aged past the 30-day cleanup window below
52
+ // are no longer retained, so they may legitimately reappear — that's the
53
+ // intended TTL behaviour, not a dedupe miss.)
54
+ const existingKeys = new Set(existing.map((f) => findingDedupeKey(f.target, f)));
47
55
  const newFindings = [];
48
56
  for (const f of rawFindings) {
49
57
  const key = findingDedupeKey(target, f);
@@ -18,6 +18,8 @@ export { watchDirectory } from './watch.js';
18
18
  export { handlePreinstallCheck } from './preinstall.js';
19
19
  export { xrayMemoryContent } from './memory-guard.js';
20
20
  export type { MemoryGuardResult } from './memory-guard.js';
21
+ export { toSarif } from './sarif.js';
22
+ export type { SarifLog } from './sarif.js';
21
23
  /**
22
24
  * Handle the `shieldcortex xray` CLI command.
23
25
  */
@@ -16,6 +16,7 @@ import { scanDirectory } from './dir-scanner.js';
16
16
  import { inspectNpmPackage } from './npm-inspector.js';
17
17
  import { calculateTrustScore } from './trust-score.js';
18
18
  import { formatXRayReport, formatXRayMarkdown } from './report.js';
19
+ import { toSarif } from './sarif.js';
19
20
  import { watchDirectory } from './watch.js';
20
21
  import { appendActivity, appendHistory, createHistoryEntry } from './activity.js';
21
22
  export { calculateTrustScore } from './trust-score.js';
@@ -27,6 +28,7 @@ export { formatXRayReport, formatXRayMarkdown } from './report.js';
27
28
  export { watchDirectory } from './watch.js';
28
29
  export { handlePreinstallCheck } from './preinstall.js';
29
30
  export { xrayMemoryContent } from './memory-guard.js';
31
+ export { toSarif } from './sarif.js';
30
32
  // ── Usage tracking ──────────────────────────────────────────
31
33
  const USAGE_FILE = path.join(os.homedir(), '.shieldcortex', 'xray-usage.json');
32
34
  const FREE_DAILY_LIMIT = 5;
@@ -84,6 +86,7 @@ export async function handleXRayCommand(args) {
84
86
  const deep = flags.has('--deep');
85
87
  const jsonOutput = flags.has('--json');
86
88
  const markdownOutput = flags.has('--markdown');
89
+ const sarifOutput = flags.has('--sarif') || args.includes('--format=sarif');
87
90
  const ciMode = flags.has('--ci');
88
91
  const watchMode = flags.has('--watch');
89
92
  const ciThreshold = (() => {
@@ -100,6 +103,7 @@ export async function handleXRayCommand(args) {
100
103
  console.error(' --deep Deep scan with full analysis (Pro)');
101
104
  console.error(' --json Output JSON result');
102
105
  console.error(' --markdown Output markdown report');
106
+ console.error(' --sarif Output SARIF 2.1.0 (GitHub Code Scanning)');
103
107
  console.error(' --ci CI/CD mode: exit code 1 if risk >= threshold');
104
108
  console.error(' --threshold=LEVEL Risk threshold for --ci (CRITICAL|HIGH|MEDIUM|LOW, default: HIGH)');
105
109
  console.error(' --watch Watch directory for changes and scan incrementally');
@@ -201,7 +205,12 @@ export async function handleXRayCommand(args) {
201
205
  : `${result.findings.length} findings across ${result.filesScanned} files`,
202
206
  });
203
207
  // Output
204
- if (jsonOutput) {
208
+ if (sarifOutput) {
209
+ // Pure SARIF JSON on stdout — nothing else, so the file can be uploaded
210
+ // straight to GitHub Code Scanning.
211
+ console.log(JSON.stringify(toSarif(result.findings), null, 2));
212
+ }
213
+ else if (jsonOutput) {
205
214
  console.log(JSON.stringify(result, null, 2));
206
215
  }
207
216
  else if (markdownOutput) {
@@ -6,6 +6,37 @@
6
6
  * Uses only Node.js built-ins (https module) — no new dependencies.
7
7
  */
8
8
  import type { XRayResult } from './types.js';
9
+ /**
10
+ * Decide whether another redirect hop may be followed. Returns the remaining
11
+ * budget for the next hop, or `null` when the cap is exhausted. Pure + exported
12
+ * so the redirect bound can be unit-tested without standing up a TLS server.
13
+ */
14
+ export declare function nextRedirectBudget(redirectsLeft: number): number | null;
15
+ /**
16
+ * Simple HTTPS GET returning the response body as a string.
17
+ *
18
+ * Bounds redirect following (max MAX_REDIRECTS hops) and applies a socket
19
+ * timeout so a hostile / mis-configured registry cannot loop or hang us.
20
+ */
21
+ export declare function httpsGet(url: string, redirectsLeft?: number): Promise<string>;
22
+ /**
23
+ * A minimal readable-stream shape: emits `data` (Buffer), then `end`, or
24
+ * `error`. Lets the decompressed-size guard be unit-tested against a tiny fake
25
+ * stream without producing a real 100 MB tarball.
26
+ */
27
+ export interface DecompressStream {
28
+ on(event: 'data', listener: (chunk: Buffer) => void): unknown;
29
+ on(event: 'end', listener: () => void): unknown;
30
+ on(event: 'error', listener: (err: Error) => void): unknown;
31
+ destroy?(err?: Error): unknown;
32
+ }
33
+ /**
34
+ * Accumulate a decompressed stream into a single Buffer, aborting if the total
35
+ * exceeds `maxBytes`. This is the gzip-bomb guard: a hostile .tgz can be tiny
36
+ * on disk yet decompress to gigabytes, so we cap the INFLATED size, not just
37
+ * the download. Pure (no fs/network) so it can be tested with a fake stream.
38
+ */
39
+ export declare function collectDecompressed(stream: DecompressStream, maxBytes?: number): Promise<Buffer>;
9
40
  /**
10
41
  * Inspect an npm package for hidden risk.
11
42
  *
@@ -14,6 +14,22 @@ import { detectPatterns } from './patterns.js';
14
14
  import { calculateTrustScore } from './trust-score.js';
15
15
  import { scanFile } from './file-scanner.js';
16
16
  // ── Constants ───────────────────────────────────────────────
17
+ /**
18
+ * DoS caps for the deep tarball scan. A hostile package can ship a tiny .tgz
19
+ * that decompresses to gigabytes (a zip/gzip "bomb"), redirect a fetch in an
20
+ * endless loop, or hang a socket open forever. These bounds keep the scanner
21
+ * from OOMing or stalling on adversarial input.
22
+ */
23
+ /** Max bytes we will download for a tarball (compressed, on the wire). */
24
+ const MAX_DOWNLOAD_BYTES = 50 * 1024 * 1024; // 50 MB
25
+ /** Max bytes a tarball may decompress to before we abort (gzip-bomb guard). */
26
+ const MAX_DECOMPRESSED_BYTES = 100 * 1024 * 1024; // 100 MB
27
+ /** Max number of entries we will extract from a single tarball. */
28
+ const MAX_TARBALL_ENTRIES = 10_000;
29
+ /** Max HTTP redirect hops to follow before giving up. */
30
+ const MAX_REDIRECTS = 5;
31
+ /** Per-request network timeout (no response / stalled socket). */
32
+ const FETCH_TIMEOUT_MS = 30_000;
17
33
  /** Popular npm packages for typosquat comparison. */
18
34
  const POPULAR_PACKAGES = [
19
35
  'react', 'express', 'lodash', 'axios', 'chalk', 'commander', 'debug',
@@ -26,14 +42,33 @@ const POPULAR_PACKAGES = [
26
42
  'redis', 'mongodb', 'sequelize', 'prisma', 'graphql', 'apollo',
27
43
  ];
28
44
  // ── Helpers ─────────────────────────────────────────────────
45
+ /**
46
+ * Decide whether another redirect hop may be followed. Returns the remaining
47
+ * budget for the next hop, or `null` when the cap is exhausted. Pure + exported
48
+ * so the redirect bound can be unit-tested without standing up a TLS server.
49
+ */
50
+ export function nextRedirectBudget(redirectsLeft) {
51
+ if (redirectsLeft <= 0)
52
+ return null;
53
+ return redirectsLeft - 1;
54
+ }
29
55
  /**
30
56
  * Simple HTTPS GET returning the response body as a string.
57
+ *
58
+ * Bounds redirect following (max MAX_REDIRECTS hops) and applies a socket
59
+ * timeout so a hostile / mis-configured registry cannot loop or hang us.
31
60
  */
32
- function httpsGet(url) {
61
+ export function httpsGet(url, redirectsLeft = MAX_REDIRECTS) {
33
62
  return new Promise((resolve, reject) => {
34
- https.get(url, { headers: { 'Accept': 'application/json' } }, (res) => {
63
+ const req = https.get(url, { headers: { 'Accept': 'application/json' } }, (res) => {
35
64
  if (res.statusCode && res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
36
- httpsGet(res.headers.location).then(resolve, reject);
65
+ res.resume(); // drain the redirect response so the socket can be reused/freed
66
+ const budget = nextRedirectBudget(redirectsLeft);
67
+ if (budget === null) {
68
+ reject(new Error(`Too many redirects (>${MAX_REDIRECTS}) for ${url}`));
69
+ return;
70
+ }
71
+ httpsGet(res.headers.location, budget).then(resolve, reject);
37
72
  return;
38
73
  }
39
74
  if (res.statusCode !== 200) {
@@ -45,75 +80,146 @@ function httpsGet(url) {
45
80
  res.on('data', (chunk) => chunks.push(chunk));
46
81
  res.on('end', () => resolve(Buffer.concat(chunks).toString('utf-8')));
47
82
  res.on('error', reject);
48
- }).on('error', reject);
83
+ });
84
+ req.setTimeout(FETCH_TIMEOUT_MS, () => {
85
+ req.destroy(new Error(`Request timed out after ${FETCH_TIMEOUT_MS}ms for ${url}`));
86
+ });
87
+ req.on('error', reject);
49
88
  });
50
89
  }
51
90
  /**
52
91
  * Download a tarball to a temp file and return the path.
92
+ *
93
+ * Bounds redirect following, applies a socket timeout, and caps the number of
94
+ * downloaded bytes (MAX_DOWNLOAD_BYTES) so an attacker cannot fill the disk or
95
+ * stream forever. The compressed cap is a first line of defence; the
96
+ * decompressed cap in extractTarball is the gzip-bomb guard.
53
97
  */
54
98
  function downloadTarball(url) {
55
99
  return new Promise((resolve, reject) => {
56
100
  const tmpFile = path.join(os.tmpdir(), `shieldcortex-xray-${Date.now()}.tgz`);
57
101
  const file = fs.createWriteStream(tmpFile);
58
- const doGet = (targetUrl) => {
59
- https.get(targetUrl, (res) => {
102
+ let settled = false;
103
+ const fail = (err) => {
104
+ if (settled)
105
+ return;
106
+ settled = true;
107
+ file.destroy();
108
+ fs.rm(tmpFile, { force: true }, () => reject(err));
109
+ };
110
+ const doGet = (targetUrl, redirectsLeft) => {
111
+ const req = https.get(targetUrl, (res) => {
60
112
  if (res.statusCode && res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
61
- doGet(res.headers.location);
113
+ res.resume();
114
+ if (redirectsLeft <= 0) {
115
+ fail(new Error(`Too many redirects (>${MAX_REDIRECTS}) downloading tarball`));
116
+ return;
117
+ }
118
+ doGet(res.headers.location, redirectsLeft - 1);
62
119
  return;
63
120
  }
64
121
  if (res.statusCode !== 200) {
65
- reject(new Error(`HTTP ${res.statusCode} downloading tarball`));
66
122
  res.resume();
123
+ fail(new Error(`HTTP ${res.statusCode} downloading tarball`));
67
124
  return;
68
125
  }
126
+ let downloaded = 0;
127
+ res.on('data', (chunk) => {
128
+ downloaded += chunk.length;
129
+ if (downloaded > MAX_DOWNLOAD_BYTES) {
130
+ req.destroy();
131
+ fail(new Error(`Tarball exceeds ${MAX_DOWNLOAD_BYTES} byte download cap`));
132
+ }
133
+ });
69
134
  res.pipe(file);
70
135
  file.on('finish', () => {
136
+ if (settled)
137
+ return;
138
+ settled = true;
71
139
  file.close();
72
140
  resolve(tmpFile);
73
141
  });
74
- }).on('error', reject);
142
+ res.on('error', fail);
143
+ });
144
+ req.setTimeout(FETCH_TIMEOUT_MS, () => {
145
+ req.destroy(new Error(`Tarball download timed out after ${FETCH_TIMEOUT_MS}ms`));
146
+ });
147
+ req.on('error', fail);
75
148
  };
76
- doGet(url);
149
+ file.on('error', fail);
150
+ doGet(url, MAX_REDIRECTS);
77
151
  });
78
152
  }
79
153
  /**
80
- * Extract a .tgz to a temp directory using Node built-ins (zlib + tar parsing).
81
- * Returns path to the extracted directory.
154
+ * Accumulate a decompressed stream into a single Buffer, aborting if the total
155
+ * exceeds `maxBytes`. This is the gzip-bomb guard: a hostile .tgz can be tiny
156
+ * on disk yet decompress to gigabytes, so we cap the INFLATED size, not just
157
+ * the download. Pure (no fs/network) so it can be tested with a fake stream.
82
158
  */
83
- async function extractTarball(tgzPath) {
84
- const extractDir = path.join(os.tmpdir(), `shieldcortex-xray-extract-${Date.now()}`);
85
- fs.mkdirSync(extractDir, { recursive: true });
159
+ export function collectDecompressed(stream, maxBytes = MAX_DECOMPRESSED_BYTES) {
86
160
  return new Promise((resolve, reject) => {
87
- const gunzip = createGunzip();
88
- const input = fs.createReadStream(tgzPath);
89
161
  const chunks = [];
90
- input.pipe(gunzip);
91
- gunzip.on('data', (chunk) => chunks.push(chunk));
92
- gunzip.on('end', () => {
93
- try {
94
- const tarData = Buffer.concat(chunks);
95
- extractTarBuffer(tarData, extractDir);
96
- resolve(extractDir);
97
- }
98
- catch (err) {
99
- reject(err);
162
+ let total = 0;
163
+ let aborted = false;
164
+ stream.on('data', (chunk) => {
165
+ if (aborted)
166
+ return;
167
+ total += chunk.length;
168
+ if (total > maxBytes) {
169
+ aborted = true;
170
+ stream.destroy?.(new Error('aborted: decompressed size cap exceeded'));
171
+ reject(new Error(`Decompressed tarball exceeds ${maxBytes} byte cap (possible gzip bomb)`));
172
+ return;
100
173
  }
174
+ chunks.push(chunk);
175
+ });
176
+ stream.on('end', () => {
177
+ if (aborted)
178
+ return;
179
+ resolve(Buffer.concat(chunks));
180
+ });
181
+ stream.on('error', (err) => {
182
+ if (aborted)
183
+ return;
184
+ reject(err);
101
185
  });
102
- gunzip.on('error', reject);
103
- input.on('error', reject);
104
186
  });
105
187
  }
188
+ /**
189
+ * Extract a .tgz to a temp directory using Node built-ins (zlib + tar parsing).
190
+ * Returns path to the extracted directory.
191
+ *
192
+ * Enforces the decompressed-size cap (gzip-bomb guard) while inflating and the
193
+ * entry-count cap while parsing the tar.
194
+ */
195
+ async function extractTarball(tgzPath) {
196
+ const extractDir = path.join(os.tmpdir(), `shieldcortex-xray-extract-${Date.now()}`);
197
+ fs.mkdirSync(extractDir, { recursive: true });
198
+ const gunzip = createGunzip();
199
+ const input = fs.createReadStream(tgzPath);
200
+ input.on('error', (err) => gunzip.destroy(err));
201
+ input.pipe(gunzip);
202
+ const tarData = await collectDecompressed(gunzip);
203
+ extractTarBuffer(tarData, extractDir);
204
+ return extractDir;
205
+ }
106
206
  /**
107
207
  * Minimal tar extraction from a buffer. Handles ustar format.
108
208
  */
109
209
  function extractTarBuffer(buf, outDir) {
110
210
  let offset = 0;
211
+ let entries = 0;
111
212
  while (offset < buf.length - 512) {
112
213
  // Read header (512 bytes)
113
214
  const header = buf.subarray(offset, offset + 512);
114
215
  // Check for empty block (end of archive)
115
216
  if (header.every(b => b === 0))
116
217
  break;
218
+ // Entry-count cap: a hostile tarball can pack millions of tiny entries to
219
+ // exhaust inodes / fd churn even within the decompressed-size cap.
220
+ if (++entries > MAX_TARBALL_ENTRIES) {
221
+ throw new Error(`Tarball exceeds ${MAX_TARBALL_ENTRIES} entry cap`);
222
+ }
117
223
  // Extract filename (0-100 bytes, null-terminated)
118
224
  const nameEnd = header.indexOf(0, 0);
119
225
  const name = header.subarray(0, Math.min(nameEnd, 100)).toString('utf-8');
@@ -4,7 +4,7 @@
4
4
  * Comprehensive pattern groups for detecting hidden risk in packages, files,
5
5
  * and metadata. Follows the same conventions as skill-scanner/patterns.ts:
6
6
  * - safeRegexTest wrapper for every test
7
- * - MAX_SCAN_LENGTH truncation to prevent ReDOS
7
+ * - Overlapping windowed scanning to bound per-regex work (ReDOS guard)
8
8
  * - PatternGroup style with weighted confidence
9
9
  * - One match per group is enough (break after first)
10
10
  */
@@ -4,21 +4,11 @@
4
4
  * Comprehensive pattern groups for detecting hidden risk in packages, files,
5
5
  * and metadata. Follows the same conventions as skill-scanner/patterns.ts:
6
6
  * - safeRegexTest wrapper for every test
7
- * - MAX_SCAN_LENGTH truncation to prevent ReDOS
7
+ * - Overlapping windowed scanning to bound per-regex work (ReDOS guard)
8
8
  * - PatternGroup style with weighted confidence
9
9
  * - One match per group is enough (break after first)
10
10
  */
11
- // ── Constants ───────────────────────────────────────────────────────────────
12
- /** Maximum content length to analyse (prevents ReDOS on very long inputs). */
13
- const MAX_SCAN_LENGTH = 50000;
14
- // ── Helpers ─────────────────────────────────────────────────────────────────
15
- /**
16
- * Safely test a regex against content with a length limit.
17
- */
18
- function safeRegexTest(pattern, text) {
19
- const truncated = text.length > MAX_SCAN_LENGTH ? text.slice(0, MAX_SCAN_LENGTH) : text;
20
- return pattern.test(truncated);
21
- }
11
+ import { forEachWindow } from '../defence/scan-windows.js';
22
12
  // ── Pattern Groups ──────────────────────────────────────────────────────────
23
13
  const XRAY_PATTERN_GROUPS = [
24
14
  // 1. eval/exec with dynamic input
@@ -210,19 +200,26 @@ const XRAY_PATTERN_GROUPS = [
210
200
  */
211
201
  export function detectPatterns(content, filePath) {
212
202
  const findings = [];
213
- const truncated = content.length > MAX_SCAN_LENGTH ? content.slice(0, MAX_SCAN_LENGTH) : content;
214
203
  for (const group of XRAY_PATTERN_GROUPS) {
215
204
  for (const pattern of group.patterns) {
216
- if (safeRegexTest(pattern, truncated)) {
217
- const match = pattern.exec(truncated);
218
- let line;
219
- let evidence;
220
- if (match) {
221
- // Calculate line number from match index
222
- const before = truncated.slice(0, match.index);
223
- line = (before.match(/\n/g) || []).length + 1;
224
- evidence = match[0].slice(0, 120);
225
- }
205
+ // Scan the WHOLE content as overlapping windows (<= SCAN_WINDOW_SIZE each)
206
+ // instead of truncating to the first 50KB, so a finding buried past the
207
+ // cap is still detected. `start` is the window's absolute char offset, used
208
+ // to translate the window-local match index back to a content-absolute one
209
+ // for an accurate line number.
210
+ let line;
211
+ let evidence;
212
+ const matched = forEachWindow(content, (window, start) => {
213
+ const match = pattern.exec(window);
214
+ if (!match)
215
+ return false;
216
+ const absoluteIndex = start + match.index;
217
+ const before = content.slice(0, absoluteIndex);
218
+ line = (before.match(/\n/g) || []).length + 1;
219
+ evidence = match[0].slice(0, 120);
220
+ return true;
221
+ });
222
+ if (matched) {
226
223
  findings.push({
227
224
  severity: group.severity,
228
225
  category: group.category,
@@ -0,0 +1,78 @@
1
+ /**
2
+ * SARIF 2.1.0 output for ShieldCortex findings.
3
+ *
4
+ * Phase 15b — turns X-Ray / audit / mcp-scan findings into a SARIF 2.1.0
5
+ * document so they surface in GitHub Code Scanning (the Security tab).
6
+ *
7
+ * Lives in the xray layer (its `index.ts` already re-exports the other
8
+ * formatters) but is shape-agnostic: it accepts BOTH the xray `XRayFinding`
9
+ * and the audit `AuditFinding` via a single internal normaliser, so the SARIF
10
+ * builder never branches on the source shape.
11
+ *
12
+ * Spec: https://docs.oasis-open.org/sarif/sarif/v2.1.0/sarif-v2.1.0.html
13
+ */
14
+ import type { XRayFinding } from './types.js';
15
+ import type { AuditFinding } from '../audit/types.js';
16
+ export type SarifLevel = 'error' | 'warning' | 'note' | 'none';
17
+ export interface SarifRule {
18
+ id: string;
19
+ name?: string;
20
+ shortDescription?: {
21
+ text: string;
22
+ };
23
+ helpUri?: string;
24
+ }
25
+ export interface SarifArtifactLocation {
26
+ uri: string;
27
+ }
28
+ export interface SarifRegion {
29
+ startLine: number;
30
+ }
31
+ export interface SarifPhysicalLocation {
32
+ artifactLocation: SarifArtifactLocation;
33
+ region?: SarifRegion;
34
+ }
35
+ export interface SarifLogicalLocation {
36
+ fullyQualifiedName: string;
37
+ kind?: string;
38
+ }
39
+ export interface SarifLocation {
40
+ physicalLocation?: SarifPhysicalLocation;
41
+ logicalLocations?: SarifLogicalLocation[];
42
+ }
43
+ export interface SarifResult {
44
+ ruleId: string;
45
+ level: SarifLevel;
46
+ message: {
47
+ text: string;
48
+ };
49
+ locations?: SarifLocation[];
50
+ }
51
+ export interface SarifDriver {
52
+ name: string;
53
+ version: string;
54
+ informationUri: string;
55
+ rules: SarifRule[];
56
+ }
57
+ export interface SarifRun {
58
+ tool: {
59
+ driver: SarifDriver;
60
+ };
61
+ results: SarifResult[];
62
+ }
63
+ export interface SarifLog {
64
+ $schema: string;
65
+ version: '2.1.0';
66
+ runs: SarifRun[];
67
+ }
68
+ export interface ToSarifOptions {
69
+ /** Tool version recorded in tool.driver.version. Resolved from package.json when omitted. */
70
+ version?: string;
71
+ /** Base directory to make file URIs relative to (defaults to process.cwd()). */
72
+ baseDir?: string;
73
+ }
74
+ /**
75
+ * Build a SARIF 2.1.0 log from a list of findings (either shape).
76
+ * Rules are deduped into `tool.driver.rules` by ruleId.
77
+ */
78
+ export declare function toSarif(findings: (XRayFinding | AuditFinding)[], options?: ToSarifOptions): SarifLog;