secator 0.16.5__tar.gz → 0.18.0__tar.gz

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.

Potentially problematic release.


This version of secator might be problematic. Click here for more details.

Files changed (217) hide show
  1. {secator-0.16.5 → secator-0.18.0}/.docker/build_all.sh +13 -1
  2. secator-0.18.0/.dockerignore +4 -0
  3. {secator-0.16.5 → secator-0.18.0}/.gitignore +3 -0
  4. {secator-0.16.5 → secator-0.18.0}/CHANGELOG.md +31 -0
  5. {secator-0.16.5 → secator-0.18.0}/PKG-INFO +1 -1
  6. {secator-0.16.5 → secator-0.18.0}/helm/templates/redis-service.yaml +0 -1
  7. {secator-0.16.5 → secator-0.18.0}/helm/templates/redis.yaml +6 -2
  8. secator-0.18.0/helm/templates/secator-manager.yaml +22 -0
  9. {secator-0.16.5 → secator-0.18.0}/helm/templates/secator-worker.yaml +8 -3
  10. secator-0.18.0/helm/values.yaml +58 -0
  11. {secator-0.16.5 → secator-0.18.0}/pyproject.toml +1 -1
  12. {secator-0.16.5 → secator-0.18.0}/secator/celery.py +75 -9
  13. {secator-0.16.5 → secator-0.18.0}/secator/celery_signals.py +2 -1
  14. {secator-0.16.5 → secator-0.18.0}/secator/cli.py +7 -1
  15. {secator-0.16.5 → secator-0.18.0}/secator/config.py +2 -1
  16. secator-0.18.0/secator/configs/workflows/user_hunt.yaml +24 -0
  17. {secator-0.16.5 → secator-0.18.0}/secator/configs/workflows/wordpress.yaml +13 -0
  18. {secator-0.16.5 → secator-0.18.0}/secator/hooks/gcs.py +11 -1
  19. {secator-0.16.5 → secator-0.18.0}/secator/hooks/mongodb.py +71 -66
  20. {secator-0.16.5 → secator-0.18.0}/secator/installer.py +1 -1
  21. {secator-0.16.5 → secator-0.18.0}/secator/output_types/certificate.py +1 -1
  22. {secator-0.16.5 → secator-0.18.0}/secator/output_types/exploit.py +1 -1
  23. {secator-0.16.5 → secator-0.18.0}/secator/output_types/ip.py +1 -1
  24. {secator-0.16.5 → secator-0.18.0}/secator/output_types/progress.py +1 -1
  25. {secator-0.16.5 → secator-0.18.0}/secator/output_types/record.py +1 -1
  26. {secator-0.16.5 → secator-0.18.0}/secator/output_types/stat.py +1 -1
  27. {secator-0.16.5 → secator-0.18.0}/secator/output_types/state.py +1 -1
  28. {secator-0.16.5 → secator-0.18.0}/secator/output_types/subdomain.py +1 -1
  29. {secator-0.16.5 → secator-0.18.0}/secator/output_types/tag.py +1 -1
  30. {secator-0.16.5 → secator-0.18.0}/secator/output_types/target.py +1 -1
  31. {secator-0.16.5 → secator-0.18.0}/secator/output_types/user_account.py +1 -1
  32. {secator-0.16.5 → secator-0.18.0}/secator/output_types/vulnerability.py +1 -1
  33. {secator-0.16.5 → secator-0.18.0}/secator/runners/_base.py +8 -8
  34. {secator-0.16.5 → secator-0.18.0}/secator/runners/command.py +29 -11
  35. {secator-0.16.5 → secator-0.18.0}/secator/tasks/bup.py +1 -1
  36. {secator-0.16.5 → secator-0.18.0}/secator/tasks/cariddi.py +37 -1
  37. {secator-0.16.5 → secator-0.18.0}/secator/tasks/dalfox.py +2 -2
  38. {secator-0.16.5 → secator-0.18.0}/secator/tasks/dirsearch.py +0 -1
  39. {secator-0.16.5 → secator-0.18.0}/secator/tasks/feroxbuster.py +0 -1
  40. {secator-0.16.5 → secator-0.18.0}/secator/tasks/ffuf.py +0 -1
  41. {secator-0.16.5 → secator-0.18.0}/secator/tasks/fping.py +24 -7
  42. {secator-0.16.5 → secator-0.18.0}/secator/tasks/katana.py +3 -0
  43. {secator-0.16.5 → secator-0.18.0}/secator/tasks/maigret.py +7 -2
  44. {secator-0.16.5 → secator-0.18.0}/secator/tasks/naabu.py +1 -2
  45. {secator-0.16.5 → secator-0.18.0}/secator/tasks/nuclei.py +4 -1
  46. {secator-0.16.5 → secator-0.18.0}/secator/tasks/wpscan.py +15 -4
  47. {secator-0.16.5 → secator-0.18.0}/secator/utils.py +9 -0
  48. {secator-0.16.5 → secator-0.18.0}/tests/integration/inputs.py +1 -1
  49. {secator-0.16.5 → secator-0.18.0}/tests/integration/outputs.py +3 -3
  50. {secator-0.16.5 → secator-0.18.0}/tests/integration/test_tasks_categories.py +10 -1
  51. secator-0.16.5/.dockerignore +0 -1
  52. secator-0.16.5/helm/templates/secator-manager.yaml +0 -18
  53. secator-0.16.5/helm/values.yaml +0 -34
  54. secator-0.16.5/secator/configs/workflows/user_hunt.yaml +0 -12
  55. {secator-0.16.5 → secator-0.18.0}/.coderabbit.yaml +0 -0
  56. {secator-0.16.5 → secator-0.18.0}/.docker/Dockerfile.alpine +0 -0
  57. {secator-0.16.5 → secator-0.18.0}/.docker/Dockerfile.arch +0 -0
  58. {secator-0.16.5 → secator-0.18.0}/.docker/Dockerfile.debian +0 -0
  59. {secator-0.16.5 → secator-0.18.0}/.docker/Dockerfile.kali +0 -0
  60. {secator-0.16.5 → secator-0.18.0}/.docker/Dockerfile.osx +0 -0
  61. {secator-0.16.5 → secator-0.18.0}/.docker/Dockerfile.ubuntu +0 -0
  62. {secator-0.16.5 → secator-0.18.0}/.flake8 +0 -0
  63. {secator-0.16.5 → secator-0.18.0}/CONTRIBUTING.md +0 -0
  64. {secator-0.16.5 → secator-0.18.0}/Dockerfile +0 -0
  65. {secator-0.16.5 → secator-0.18.0}/LICENSE +0 -0
  66. {secator-0.16.5 → secator-0.18.0}/README.md +0 -0
  67. {secator-0.16.5 → secator-0.18.0}/SECURITY.md +0 -0
  68. {secator-0.16.5 → secator-0.18.0}/cloudbuild.yaml +0 -0
  69. {secator-0.16.5 → secator-0.18.0}/helm/.helmignore +0 -0
  70. {secator-0.16.5 → secator-0.18.0}/helm/Chart.yaml +0 -0
  71. {secator-0.16.5 → secator-0.18.0}/scripts/download_cves.sh +0 -0
  72. {secator-0.16.5 → secator-0.18.0}/scripts/generate_tools_md_table.py +0 -0
  73. {secator-0.16.5 → secator-0.18.0}/scripts/install.sh +0 -0
  74. {secator-0.16.5 → secator-0.18.0}/scripts/install_asciinema.sh +0 -0
  75. {secator-0.16.5 → secator-0.18.0}/scripts/install_go.sh +0 -0
  76. {secator-0.16.5 → secator-0.18.0}/scripts/install_ruby.sh +0 -0
  77. {secator-0.16.5 → secator-0.18.0}/scripts/msf/exploit_cve.rc +0 -0
  78. {secator-0.16.5 → secator-0.18.0}/scripts/msf/ftp_anonymous.rc +0 -0
  79. {secator-0.16.5 → secator-0.18.0}/scripts/msf/ftp_version.rc +0 -0
  80. {secator-0.16.5 → secator-0.18.0}/scripts/msf/ftp_vsftpd_234_backdoor.rc +0 -0
  81. {secator-0.16.5 → secator-0.18.0}/scripts/msf/redis.rc +0 -0
  82. {secator-0.16.5 → secator-0.18.0}/scripts/stories/STORY.md +0 -0
  83. {secator-0.16.5 → secator-0.18.0}/scripts/stories/aliases.sh +0 -0
  84. {secator-0.16.5 → secator-0.18.0}/scripts/stories/demo.sh +0 -0
  85. {secator-0.16.5 → secator-0.18.0}/scripts/stories/fmt.sh +0 -0
  86. {secator-0.16.5 → secator-0.18.0}/scripts/stories/input.sh +0 -0
  87. {secator-0.16.5 → secator-0.18.0}/scripts/stories/pipe.sh +0 -0
  88. {secator-0.16.5 → secator-0.18.0}/scripts/stories/short_demo.sh +0 -0
  89. {secator-0.16.5 → secator-0.18.0}/scripts/update_tools.sh +0 -0
  90. {secator-0.16.5 → secator-0.18.0}/secator/.gitignore +0 -0
  91. {secator-0.16.5 → secator-0.18.0}/secator/__init__.py +0 -0
  92. {secator-0.16.5 → secator-0.18.0}/secator/celery_utils.py +0 -0
  93. {secator-0.16.5 → secator-0.18.0}/secator/cli_helper.py +0 -0
  94. {secator-0.16.5 → secator-0.18.0}/secator/click.py +0 -0
  95. {secator-0.16.5 → secator-0.18.0}/secator/configs/__init__.py +0 -0
  96. {secator-0.16.5 → secator-0.18.0}/secator/configs/profiles/__init__.py +0 -0
  97. {secator-0.16.5 → secator-0.18.0}/secator/configs/profiles/aggressive.yaml +0 -0
  98. {secator-0.16.5 → secator-0.18.0}/secator/configs/profiles/http_headless.yaml +0 -0
  99. {secator-0.16.5 → secator-0.18.0}/secator/configs/profiles/http_record.yaml +0 -0
  100. {secator-0.16.5 → secator-0.18.0}/secator/configs/profiles/insane.yaml +0 -0
  101. {secator-0.16.5 → secator-0.18.0}/secator/configs/profiles/paranoid.yaml +0 -0
  102. {secator-0.16.5 → secator-0.18.0}/secator/configs/profiles/polite.yaml +0 -0
  103. {secator-0.16.5 → secator-0.18.0}/secator/configs/profiles/sneaky.yaml +0 -0
  104. {secator-0.16.5 → secator-0.18.0}/secator/configs/profiles/tor.yaml +0 -0
  105. {secator-0.16.5 → secator-0.18.0}/secator/configs/scans/__init__.py +0 -0
  106. {secator-0.16.5 → secator-0.18.0}/secator/configs/scans/domain.yaml +0 -0
  107. {secator-0.16.5 → secator-0.18.0}/secator/configs/scans/host.yaml +0 -0
  108. {secator-0.16.5 → secator-0.18.0}/secator/configs/scans/network.yaml +0 -0
  109. {secator-0.16.5 → secator-0.18.0}/secator/configs/scans/subdomain.yaml +0 -0
  110. {secator-0.16.5 → secator-0.18.0}/secator/configs/scans/url.yaml +0 -0
  111. {secator-0.16.5 → secator-0.18.0}/secator/configs/workflows/__init__.py +0 -0
  112. {secator-0.16.5 → secator-0.18.0}/secator/configs/workflows/cidr_recon.yaml +0 -0
  113. {secator-0.16.5 → secator-0.18.0}/secator/configs/workflows/code_scan.yaml +0 -0
  114. {secator-0.16.5 → secator-0.18.0}/secator/configs/workflows/host_recon.yaml +0 -0
  115. {secator-0.16.5 → secator-0.18.0}/secator/configs/workflows/subdomain_recon.yaml +0 -0
  116. {secator-0.16.5 → secator-0.18.0}/secator/configs/workflows/url_bypass.yaml +0 -0
  117. {secator-0.16.5 → secator-0.18.0}/secator/configs/workflows/url_crawl.yaml +0 -0
  118. {secator-0.16.5 → secator-0.18.0}/secator/configs/workflows/url_dirsearch.yaml +0 -0
  119. {secator-0.16.5 → secator-0.18.0}/secator/configs/workflows/url_fuzz.yaml +0 -0
  120. {secator-0.16.5 → secator-0.18.0}/secator/configs/workflows/url_params_fuzz.yaml +0 -0
  121. {secator-0.16.5 → secator-0.18.0}/secator/configs/workflows/url_vuln.yaml +0 -0
  122. {secator-0.16.5 → secator-0.18.0}/secator/cve.py +0 -0
  123. {secator-0.16.5 → secator-0.18.0}/secator/decorators.py +0 -0
  124. {secator-0.16.5 → secator-0.18.0}/secator/definitions.py +0 -0
  125. {secator-0.16.5 → secator-0.18.0}/secator/exporters/__init__.py +0 -0
  126. {secator-0.16.5 → secator-0.18.0}/secator/exporters/_base.py +0 -0
  127. {secator-0.16.5 → secator-0.18.0}/secator/exporters/console.py +0 -0
  128. {secator-0.16.5 → secator-0.18.0}/secator/exporters/csv.py +0 -0
  129. {secator-0.16.5 → secator-0.18.0}/secator/exporters/gdrive.py +0 -0
  130. {secator-0.16.5 → secator-0.18.0}/secator/exporters/json.py +0 -0
  131. {secator-0.16.5 → secator-0.18.0}/secator/exporters/table.py +0 -0
  132. {secator-0.16.5 → secator-0.18.0}/secator/exporters/txt.py +0 -0
  133. {secator-0.16.5 → secator-0.18.0}/secator/hooks/__init__.py +0 -0
  134. {secator-0.16.5 → secator-0.18.0}/secator/loader.py +0 -0
  135. {secator-0.16.5 → secator-0.18.0}/secator/output_types/__init__.py +0 -0
  136. {secator-0.16.5 → secator-0.18.0}/secator/output_types/_base.py +0 -0
  137. {secator-0.16.5 → secator-0.18.0}/secator/output_types/error.py +0 -0
  138. {secator-0.16.5 → secator-0.18.0}/secator/output_types/info.py +0 -0
  139. {secator-0.16.5 → secator-0.18.0}/secator/output_types/port.py +0 -0
  140. {secator-0.16.5 → secator-0.18.0}/secator/output_types/url.py +0 -0
  141. {secator-0.16.5 → secator-0.18.0}/secator/output_types/warning.py +0 -0
  142. {secator-0.16.5 → secator-0.18.0}/secator/report.py +0 -0
  143. {secator-0.16.5 → secator-0.18.0}/secator/rich.py +0 -0
  144. {secator-0.16.5 → secator-0.18.0}/secator/runners/__init__.py +0 -0
  145. {secator-0.16.5 → secator-0.18.0}/secator/runners/_helpers.py +0 -0
  146. {secator-0.16.5 → secator-0.18.0}/secator/runners/celery.py +0 -0
  147. {secator-0.16.5 → secator-0.18.0}/secator/runners/scan.py +0 -0
  148. {secator-0.16.5 → secator-0.18.0}/secator/runners/task.py +0 -0
  149. {secator-0.16.5 → secator-0.18.0}/secator/runners/workflow.py +0 -0
  150. {secator-0.16.5 → secator-0.18.0}/secator/scans/__init__.py +0 -0
  151. {secator-0.16.5 → secator-0.18.0}/secator/serializers/__init__.py +0 -0
  152. {secator-0.16.5 → secator-0.18.0}/secator/serializers/dataclass.py +0 -0
  153. {secator-0.16.5 → secator-0.18.0}/secator/serializers/json.py +0 -0
  154. {secator-0.16.5 → secator-0.18.0}/secator/serializers/regex.py +0 -0
  155. {secator-0.16.5 → secator-0.18.0}/secator/tasks/__init__.py +0 -0
  156. {secator-0.16.5 → secator-0.18.0}/secator/tasks/_categories.py +0 -0
  157. {secator-0.16.5 → secator-0.18.0}/secator/tasks/arjun.py +0 -0
  158. {secator-0.16.5 → secator-0.18.0}/secator/tasks/bbot.py +0 -0
  159. {secator-0.16.5 → secator-0.18.0}/secator/tasks/dnsx.py +0 -0
  160. {secator-0.16.5 → secator-0.18.0}/secator/tasks/gau.py +0 -0
  161. {secator-0.16.5 → secator-0.18.0}/secator/tasks/gf.py +0 -0
  162. {secator-0.16.5 → secator-0.18.0}/secator/tasks/gitleaks.py +0 -0
  163. {secator-0.16.5 → secator-0.18.0}/secator/tasks/gospider.py +0 -0
  164. {secator-0.16.5 → secator-0.18.0}/secator/tasks/grype.py +0 -0
  165. {secator-0.16.5 → secator-0.18.0}/secator/tasks/h8mail.py +0 -0
  166. {secator-0.16.5 → secator-0.18.0}/secator/tasks/httpx.py +0 -0
  167. {secator-0.16.5 → secator-0.18.0}/secator/tasks/mapcidr.py +0 -0
  168. {secator-0.16.5 → secator-0.18.0}/secator/tasks/msfconsole.py +0 -0
  169. {secator-0.16.5 → secator-0.18.0}/secator/tasks/nmap.py +0 -0
  170. {secator-0.16.5 → secator-0.18.0}/secator/tasks/searchsploit.py +0 -0
  171. {secator-0.16.5 → secator-0.18.0}/secator/tasks/subfinder.py +0 -0
  172. {secator-0.16.5 → secator-0.18.0}/secator/tasks/testssl.py +0 -0
  173. {secator-0.16.5 → secator-0.18.0}/secator/tasks/trivy.py +0 -0
  174. {secator-0.16.5 → secator-0.18.0}/secator/tasks/wafw00f.py +0 -0
  175. {secator-0.16.5 → secator-0.18.0}/secator/tasks/wpprobe.py +0 -0
  176. {secator-0.16.5 → secator-0.18.0}/secator/template.py +0 -0
  177. {secator-0.16.5 → secator-0.18.0}/secator/thread.py +0 -0
  178. {secator-0.16.5 → secator-0.18.0}/secator/tree.py +0 -0
  179. {secator-0.16.5 → secator-0.18.0}/secator/utils_test.py +0 -0
  180. {secator-0.16.5 → secator-0.18.0}/secator/workflows/__init__.py +0 -0
  181. {secator-0.16.5 → secator-0.18.0}/tests/__init__.py +0 -0
  182. {secator-0.16.5 → secator-0.18.0}/tests/fixtures/h8mail_breach.txt +0 -0
  183. {secator-0.16.5 → secator-0.18.0}/tests/fixtures/ls.py +0 -0
  184. {secator-0.16.5 → secator-0.18.0}/tests/fixtures/msfconsole_input.rc +0 -0
  185. {secator-0.16.5 → secator-0.18.0}/tests/fixtures/nmap_output.xml +0 -0
  186. {secator-0.16.5 → secator-0.18.0}/tests/integration/__init__.py +0 -0
  187. {secator-0.16.5 → secator-0.18.0}/tests/integration/all.yaml +0 -0
  188. {secator-0.16.5 → secator-0.18.0}/tests/integration/setup.sh +0 -0
  189. {secator-0.16.5 → secator-0.18.0}/tests/integration/teardown.sh +0 -0
  190. {secator-0.16.5 → secator-0.18.0}/tests/integration/test_addons.py +0 -0
  191. {secator-0.16.5 → secator-0.18.0}/tests/integration/test_celery.py +0 -0
  192. {secator-0.16.5 → secator-0.18.0}/tests/integration/test_scans.py +0 -0
  193. {secator-0.16.5 → secator-0.18.0}/tests/integration/test_tasks.py +0 -0
  194. {secator-0.16.5 → secator-0.18.0}/tests/integration/test_worker.py +0 -0
  195. {secator-0.16.5 → secator-0.18.0}/tests/integration/test_workflows.py +0 -0
  196. {secator-0.16.5 → secator-0.18.0}/tests/integration/wordlist.txt +0 -0
  197. {secator-0.16.5 → secator-0.18.0}/tests/integration/wordlist_dns.txt +0 -0
  198. {secator-0.16.5 → secator-0.18.0}/tests/integration/wordpress_toolbox/Dockerfile +0 -0
  199. {secator-0.16.5 → secator-0.18.0}/tests/integration/wordpress_toolbox/Makefile +0 -0
  200. {secator-0.16.5 → secator-0.18.0}/tests/performance/__init__.py +0 -0
  201. {secator-0.16.5 → secator-0.18.0}/tests/performance/loadtester.py +0 -0
  202. {secator-0.16.5 → secator-0.18.0}/tests/performance/test_worker.py +0 -0
  203. {secator-0.16.5 → secator-0.18.0}/tests/template/test_templates.py +0 -0
  204. {secator-0.16.5 → secator-0.18.0}/tests/unit/__init__.py +0 -0
  205. {secator-0.16.5 → secator-0.18.0}/tests/unit/test_celery.py +0 -0
  206. {secator-0.16.5 → secator-0.18.0}/tests/unit/test_cli.py +0 -0
  207. {secator-0.16.5 → secator-0.18.0}/tests/unit/test_command.py +0 -0
  208. {secator-0.16.5 → secator-0.18.0}/tests/unit/test_config.py +0 -0
  209. {secator-0.16.5 → secator-0.18.0}/tests/unit/test_offline.py +0 -0
  210. {secator-0.16.5 → secator-0.18.0}/tests/unit/test_runners.py +0 -0
  211. {secator-0.16.5 → secator-0.18.0}/tests/unit/test_runners_helpers.py +0 -0
  212. {secator-0.16.5 → secator-0.18.0}/tests/unit/test_scans.py +0 -0
  213. {secator-0.16.5 → secator-0.18.0}/tests/unit/test_serializers.py +0 -0
  214. {secator-0.16.5 → secator-0.18.0}/tests/unit/test_tasks.py +0 -0
  215. {secator-0.16.5 → secator-0.18.0}/tests/unit/test_tasks_categories.py +0 -0
  216. {secator-0.16.5 → secator-0.18.0}/tests/unit/test_template.py +0 -0
  217. {secator-0.16.5 → secator-0.18.0}/tests/unit/test_utils.py +0 -0
@@ -2,16 +2,28 @@
2
2
 
3
3
  # Define an array of distributions
4
4
  DISTROS=("alpine" "arch" "debian" "kali" "osx" "ubuntu")
5
+ BUILDER=$(which docker || which podman || which buildah)
6
+
7
+ if [ -z "$BUILDER" ]; then
8
+ echo "Error: No container builder found (docker, podman, or buildah required)"
9
+ exit 1
10
+ fi
11
+
12
+ echo "Using builder: $BUILDER"
13
+
14
+ mkdir -p .docker/logs/
5
15
 
6
16
  # Function to build an image
7
17
  build_image() {
8
18
  local DISTRO=$1
9
19
  local DOCKERFILE=".docker/Dockerfile.${DISTRO}"
20
+ local STDOUT_LOG=".docker/logs/${DISTRO}.stdout"
21
+ local STDERR_LOG=".docker/logs/${DISTRO}.stderr"
10
22
  local IMAGE_NAME="secator-${DISTRO}"
11
23
 
12
24
  if [ -f "$DOCKERFILE" ]; then
13
25
  echo "🚀 Building $IMAGE_NAME using $DOCKERFILE..."
14
- docker build -t "$IMAGE_NAME" -f "$DOCKERFILE" . && \
26
+ $BUILDER build -t "$IMAGE_NAME" -f "$DOCKERFILE" . > $STDOUT_LOG 2> $STDERR_LOG && \
15
27
  echo "✅ Successfully built $IMAGE_NAME" || \
16
28
  echo "❌ Failed to build $IMAGE_NAME"
17
29
  else
@@ -0,0 +1,4 @@
1
+ .docker/logs
2
+ .git
3
+ .github
4
+ .gitignore
@@ -1,3 +1,6 @@
1
+ # Build logs
2
+ .docker/logs
3
+
1
4
  # Byte-compiled / optimized / DLL files
2
5
  __pycache__/
3
6
  *.py[cod]
@@ -1,5 +1,36 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.18.0](https://github.com/freelabz/secator/compare/v0.17.0...v0.18.0) (2025-10-22)
4
+
5
+
6
+ ### Features
7
+
8
+ * **workflow:** update user hunt ([#688](https://github.com/freelabz/secator/issues/688)) ([e4f3e29](https://github.com/freelabz/secator/commit/e4f3e294c1668c66ed893305b0147df37cb4453a))
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * broken sudo prompt because of os.setsid ([#722](https://github.com/freelabz/secator/issues/722)) ([5c77957](https://github.com/freelabz/secator/commit/5c77957cb78533b7e819c01c19de6e46eae0d2af))
14
+ * bugs and warnings in task data ([#714](https://github.com/freelabz/secator/issues/714)) ([845415b](https://github.com/freelabz/secator/commit/845415bb337f77867d49be66bbd23eaf307e5848))
15
+ * bup file flag ([#725](https://github.com/freelabz/secator/issues/725)) ([0622ef5](https://github.com/freelabz/secator/commit/0622ef509b1dc33996dd5e89aea5cd802160744d))
16
+ * context propagation for subtasks ([#720](https://github.com/freelabz/secator/issues/720)) ([d636aa6](https://github.com/freelabz/secator/commit/d636aa66562fd030299fce20f3abaeca283eaf74))
17
+ * **fping:** remove bad options, add new ones ([#713](https://github.com/freelabz/secator/issues/713)) ([4356b4f](https://github.com/freelabz/secator/commit/4356b4f120043e2f94973a9c0061345a06efaeda))
18
+ * maigret version pin ([#721](https://github.com/freelabz/secator/issues/721)) ([488b5a1](https://github.com/freelabz/secator/commit/488b5a1b994e6d3dfadc409d09aaaeb93ff60fb4))
19
+ * subfinder integration tests ([#724](https://github.com/freelabz/secator/issues/724)) ([8163152](https://github.com/freelabz/secator/commit/8163152efb09f3854ec9fa7125b16084eda4c98f))
20
+ * wpscan errors and wordpress workflow ([#723](https://github.com/freelabz/secator/issues/723)) ([8ee32aa](https://github.com/freelabz/secator/commit/8ee32aacb1310cfb833bdcf696477ae29eb271c7))
21
+
22
+ ## [0.17.0](https://github.com/freelabz/secator/compare/v0.16.5...v0.17.0) (2025-09-06)
23
+
24
+
25
+ ### Features
26
+
27
+ * enforceable memory limits ([#710](https://github.com/freelabz/secator/issues/710)) ([eaefa1f](https://github.com/freelabz/secator/commit/eaefa1f5497af4d6a6020e09d5f954ae4639f20c))
28
+
29
+
30
+ ### Bug Fixes
31
+
32
+ * prod optimizations ([#708](https://github.com/freelabz/secator/issues/708)) ([efb5d3c](https://github.com/freelabz/secator/commit/efb5d3ce637a5de6e23ed157fd85d2a39bef360d))
33
+
3
34
  ## [0.16.5](https://github.com/freelabz/secator/compare/v0.16.4...v0.16.5) (2025-06-25)
4
35
 
5
36
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: secator
3
- Version: 0.16.5
3
+ Version: 0.18.0
4
4
  Summary: The pentester's swiss knife.
5
5
  Project-URL: Homepage, https://github.com/freelabz/secator
6
6
  Project-URL: Issues, https://github.com/freelabz/secator/issues
@@ -2,7 +2,6 @@ apiVersion: v1
2
2
  kind: Service
3
3
  metadata:
4
4
  name: {{ .Values.redis.name }}
5
- namespace: {{ .Values.namespace }}
6
5
  spec:
7
6
  type: ClusterIP
8
7
  ports:
@@ -2,7 +2,6 @@ apiVersion: apps/v1
2
2
  kind: StatefulSet
3
3
  metadata:
4
4
  name: {{ .Values.redis.name }}
5
- namespace: {{ .Values.namespace }}
6
5
  spec:
7
6
  selector:
8
7
  matchLabels:
@@ -13,10 +12,15 @@ spec:
13
12
  metadata:
14
13
  labels:
15
14
  app: redis
16
- spec:
15
+ spec:
16
+ automountServiceAccountToken: {{ .Values.automountServiceAccountToken }}
17
17
  containers:
18
18
  - name: {{ .Values.redis.name }}
19
19
  image: {{ .Values.redis.image }}
20
+ securityContext:
21
+ {{- toYaml .Values.redis.securityContext | nindent 10 }}
22
+ resources:
23
+ {{- toYaml .Values.redis.resources | nindent 10 }}
20
24
  ports:
21
25
  - containerPort: {{ .Values.redis.port }}
22
26
  name: client
@@ -0,0 +1,22 @@
1
+ apiVersion: v1
2
+ kind: Pod
3
+ metadata:
4
+ name: {{ .Values.secatorManager.name }}
5
+ labels:
6
+ name: secator-manager
7
+ spec:
8
+ automountServiceAccountToken: {{ .Values.automountServiceAccountToken }}
9
+ containers:
10
+ - name: secator-manager
11
+ image: {{ .Values.secatorManager.image }}
12
+ securityContext:
13
+ {{- toYaml .Values.secatorManager.securityContext | nindent 6 }}
14
+ resources:
15
+ {{- toYaml .Values.secatorManager.resources | nindent 6 }}
16
+ command: ["sleep"]
17
+ args: ["infinity"]
18
+ env:
19
+ - name: SECATOR_CELERY_BROKER_URL
20
+ value: "redis://{{ .Values.redis.name }}:{{ .Values.redis.port }}/0"
21
+ - name: SECATOR_CELERY_RESULT_BACKEND
22
+ value: "redis://{{ .Values.redis.name }}:{{ .Values.redis.port }}/0"
@@ -2,8 +2,8 @@ apiVersion: apps/v1
2
2
  kind: Deployment
3
3
  metadata:
4
4
  name: {{ .Values.secatorWorker.name }}
5
- namespace: {{ .Values.namespace }}
6
5
  spec:
6
+ replicas: {{ .Values.secatorWorker.replicas }}
7
7
  selector:
8
8
  matchLabels:
9
9
  app: secator-worker
@@ -12,13 +12,18 @@ spec:
12
12
  labels:
13
13
  app: secator-worker
14
14
  spec:
15
+ automountServiceAccountToken: {{ .Values.automountServiceAccountToken }}
15
16
  containers:
16
17
  - name: {{ .Values.secatorWorker.name }}
17
18
  image: {{ .Values.secatorWorker.image }}
19
+ securityContext:
20
+ {{- toYaml .Values.secatorWorker.securityContext | nindent 10 }}
21
+ resources:
22
+ {{- toYaml .Values.secatorWorker.resources | nindent 10 }}
18
23
  command: ["secator"]
19
24
  args: ["worker"]
20
25
  env:
21
26
  - name: SECATOR_CELERY_BROKER_URL
22
- value: "redis://{{ .Values.redis.name }}:6379/0"
27
+ value: "redis://{{ .Values.redis.name }}:{{ .Values.redis.port }}/0"
23
28
  - name: SECATOR_CELERY_RESULT_BACKEND
24
- value: "redis://{{ .Values.redis.name }}:6379/0"
29
+ value: "redis://{{ .Values.redis.name }}:{{ .Values.redis.port }}/0"
@@ -0,0 +1,58 @@
1
+ # Default values for Secator
2
+ # This is a YAML-formatted file.
3
+ # Declare variables to be passed into your templates.
4
+
5
+ # TODO: Create service accounts instead. Assess for RBAC. Add tooling for kubernetes to image, or side-car.
6
+ # For instance, the secator Manager pod could have sufficient access to list/get/set worker replicas for scaling from
7
+ # from the pod itself. Perhaps another add-on?
8
+ automountServiceAccountToken: false
9
+
10
+ secatorManager:
11
+ name: secator-manager
12
+ image: "freelabz/secator"
13
+ securityContext: {}
14
+
15
+ # resources: cpu/memory requests and limits for managers
16
+ resources: {}
17
+
18
+ # Empty if using default repository
19
+ repository:
20
+ # Empty if using tag "latest"
21
+ tag:
22
+
23
+ secatorWorker:
24
+ name: secator-worker
25
+ image: "freelabz/secator"
26
+ securityContext: {}
27
+
28
+ # resources: cpu/memory requests and limits for workers
29
+ resources: {}
30
+ replicas: 1
31
+
32
+ # Empty if using default repository
33
+ repository:
34
+ # Empty if using tag "latest"
35
+ tag:
36
+
37
+ redis:
38
+ name: redis
39
+ image: "redis:alpine"
40
+ # Run redis with least privilege.
41
+ securityContext:
42
+ runAsUser: 999
43
+ runAsGroup: 1000
44
+ runAsNonRoot: true
45
+ allowPrivilegeEscalation: false
46
+ readOnlyRootFilesystem: true
47
+ capabilities:
48
+ drop:
49
+ - ALL
50
+ # resources: cpu/memory requests and limits for redis
51
+ resources: {}
52
+
53
+ # Empty if using default repository
54
+ repository:
55
+ # Empty if using tag "latest"
56
+ tag:
57
+ replicas: 1
58
+ port: 6379
@@ -4,7 +4,7 @@ build-backend = 'hatchling.build'
4
4
 
5
5
  [project]
6
6
  name = 'secator'
7
- version = "0.16.5"
7
+ version = "0.18.0"
8
8
  authors = [{ name = 'FreeLabz', email = 'sales@freelabz.com' }]
9
9
  readme = 'README.md'
10
10
  description = "The pentester's swiss knife."
@@ -1,3 +1,4 @@
1
+ import gc
1
2
  import json
2
3
  import logging
3
4
  import os
@@ -5,6 +6,7 @@ import os
5
6
  from time import time
6
7
 
7
8
  from celery import Celery, chord
9
+ from celery.canvas import signature
8
10
  from celery.app import trace
9
11
 
10
12
  from rich.logging import RichHandler
@@ -61,9 +63,10 @@ app.conf.update({
61
63
  'result_backend': CONFIG.celery.result_backend,
62
64
  'result_expires': CONFIG.celery.result_expires,
63
65
  'result_backend_transport_options': json.loads(CONFIG.celery.result_backend_transport_options) if CONFIG.celery.result_backend_transport_options else {}, # noqa: E501
64
- 'result_extended': True,
66
+ 'result_extended': not CONFIG.addons.mongodb.enabled,
65
67
  'result_backend_thread_safe': True,
66
68
  'result_serializer': 'pickle',
69
+ 'result_accept_content': ['application/x-python-serialize'],
67
70
 
68
71
  # Task config
69
72
  'task_acks_late': CONFIG.celery.task_acks_late,
@@ -81,6 +84,11 @@ app.conf.update({
81
84
  'task_store_eager_result': True,
82
85
  'task_send_sent_event': CONFIG.celery.task_send_sent_event,
83
86
  'task_serializer': 'pickle',
87
+ 'task_accept_content': ['application/x-python-serialize'],
88
+
89
+ # Event config
90
+ 'event_serializer': 'pickle',
91
+ 'event_accept_content': ['application/x-python-serialize'],
84
92
 
85
93
  # Worker config
86
94
  # 'worker_direct': True, # TODO: consider enabling this to allow routing to specific workers
@@ -168,6 +176,12 @@ def run_scan(self, args=[], kwargs={}):
168
176
 
169
177
  @app.task(bind=True)
170
178
  def run_command(self, results, name, targets, opts={}):
179
+ # Set Celery request id in context
180
+ context = opts.get('context', {})
181
+ context['celery_id'] = self.request.id
182
+ context['worker_name'] = os.environ.get('WORKER_NAME', 'unknown')
183
+
184
+ # Set routing key in context
171
185
  if IN_CELERY_WORKER_PROCESS:
172
186
  quiet = not CONFIG.cli.worker_command_verbose
173
187
  opts.update({
@@ -179,15 +193,13 @@ def run_command(self, results, name, targets, opts={}):
179
193
  'quiet': quiet
180
194
  })
181
195
  routing_key = self.request.delivery_info['routing_key']
196
+ context['routing_key'] = routing_key
182
197
  debug(f'Task "{name}" running with routing key "{routing_key}"', sub='celery.state')
183
198
 
184
199
  # Flatten + dedupe + filter results
185
200
  results = forward_results(results)
186
201
 
187
- # Set Celery request id in context
188
- context = opts.get('context', {})
189
- context['celery_id'] = self.request.id
190
- context['worker_name'] = os.environ.get('WORKER_NAME', 'unknown')
202
+ # Set task opts
191
203
  opts['context'] = context
192
204
  opts['results'] = results
193
205
  opts['sync'] = True
@@ -204,10 +216,13 @@ def run_command(self, results, name, targets, opts={}):
204
216
  # Chunk task if needed
205
217
  if chunk_it:
206
218
  if IN_CELERY_WORKER_PROCESS:
207
- console.print(Info(message=f'Task {name} requires chunking, breaking into {len(targets)} tasks'))
208
- tasks = break_task(task, opts, results=results)
219
+ console.print(Info(message=f'Task {name} requires chunking'))
220
+ workflow = break_task(task, opts, results=results)
221
+ if IN_CELERY_WORKER_PROCESS:
222
+ console.print(Info(message=f'Task {name} successfully broken into {len(workflow)} chunks'))
209
223
  update_state(self, task, force=True)
210
- return self.replace(tasks)
224
+ console.print(Info(message=f'Task {name} updated state, replacing task with Celery chord workflow'))
225
+ return replace(self, workflow)
211
226
 
212
227
  # Update state live
213
228
  for _ in task:
@@ -327,6 +342,52 @@ def is_celery_worker_alive():
327
342
  return result
328
343
 
329
344
 
345
+ def replace(task_instance, sig):
346
+ """Replace this task, with a new task inheriting the task id.
347
+
348
+ Execution of the host task ends immediately and no subsequent statements
349
+ will be run.
350
+
351
+ .. versionadded:: 4.0
352
+
353
+ Arguments:
354
+ sig (Signature): signature to replace with.
355
+ visitor (StampingVisitor): Visitor API object.
356
+
357
+ Raises:
358
+ ~@Ignore: This is always raised when called in asynchronous context.
359
+ It is best to always use ``return self.replace(...)`` to convey
360
+ to the reader that the task won't continue after being replaced.
361
+ """
362
+ console.print('Replacing task')
363
+ chord = task_instance.request.chord
364
+ sig.freeze(task_instance.request.id)
365
+ replaced_task_nesting = task_instance.request.get('replaced_task_nesting', 0) + 1
366
+ sig.set(
367
+ chord=chord,
368
+ group_id=task_instance.request.group,
369
+ group_index=task_instance.request.group_index,
370
+ root_id=task_instance.request.root_id,
371
+ replaced_task_nesting=replaced_task_nesting
372
+ )
373
+ import psutil
374
+ import os
375
+ process = psutil.Process(os.getpid())
376
+ length = len(task_instance.request.chain) if task_instance.request.chain else 0
377
+ console.print(f'Adding {length} chain tasks from request chain')
378
+ for ix, t in enumerate(reversed(task_instance.request.chain or [])):
379
+ console.print(f'Adding chain task {t.name} from request chain ({ix + 1}/{length})')
380
+ chain_task = signature(t, app=task_instance.app)
381
+ chain_task.set(replaced_task_nesting=replaced_task_nesting)
382
+ sig |= chain_task
383
+ del chain_task
384
+ del t
385
+ memory_bytes = process.memory_info().rss
386
+ console.print(f'Memory usage: {memory_bytes / 1024 / 1024:.2f} MB (chain task {ix + 1}/{length})')
387
+ gc.collect()
388
+ return task_instance.on_replace(sig)
389
+
390
+
330
391
  def break_task(task, task_opts, results=[]):
331
392
  """Break a task into multiple of the same type."""
332
393
  chunks = task.inputs
@@ -370,16 +431,21 @@ def break_task(task, task_opts, results=[]):
370
431
  task_id = sig.freeze().task_id
371
432
  full_name = f'{task.name}_{ix + 1}'
372
433
  task.add_subtask(task_id, task.name, full_name)
373
- info = Info(message=f'Celery chunked task created: {task_id}')
434
+ info = Info(message=f'Celery chunked task created ({ix + 1} / {len(chunks)}): {task_id}')
374
435
  task.add_result(info)
375
436
  sigs.append(sig)
376
437
 
377
438
  # Mark main task as async since it's being chunked
378
439
  task.sync = False
440
+ task.results = []
441
+ task.uuids = set()
442
+ console.print(Info(message=f'Task {task.unique_name} is now async, building chord with{len(sigs)} chunks'))
443
+ console.print(Info(message=f'Results: {results}'))
379
444
 
380
445
  # Build Celery workflow
381
446
  workflow = chord(
382
447
  tuple(sigs),
383
448
  mark_runner_completed.s(runner=task).set(queue='results')
384
449
  )
450
+ console.print(Info(message=f'Task {task.unique_name} chord built with {len(sigs)} chunks, returning workflow'))
385
451
  return workflow
@@ -92,8 +92,9 @@ def task_postrun_handler(**kwargs):
92
92
 
93
93
  # Get sender name from kwargs
94
94
  sender_name = kwargs['sender'].name
95
+ # console.print(Info(message=f'Task postrun handler --> Sender name: {sender_name}'))
95
96
 
96
- if CONFIG.celery.worker_kill_after_task and sender_name.startswith('secator.'):
97
+ if CONFIG.celery.worker_kill_after_task and (sender_name.startswith('secator.') or sender_name.startswith('api.')):
97
98
  worker_name = os.environ.get('WORKER_NAME', 'unknown')
98
99
  console.print(Info(message=f'Shutdown worker {worker_name} since config celery.worker_kill_after_task is set.'))
99
100
  kill_worker(parent=True)
@@ -134,7 +134,10 @@ for config in SCANS:
134
134
  @click.option('--stop', is_flag=True, help='Stop a worker in dev mode (celery multi).')
135
135
  @click.option('--show', is_flag=True, help='Show command (celery multi).')
136
136
  @click.option('--use-command-runner', is_flag=True, default=False, help='Use command runner to run the command.')
137
- def worker(hostname, concurrency, reload, queue, pool, quiet, loglevel, check, dev, stop, show, use_command_runner):
137
+ @click.option('--without-gossip', is_flag=True)
138
+ @click.option('--without-mingle', is_flag=True)
139
+ @click.option('--without-heartbeat', is_flag=True)
140
+ def worker(hostname, concurrency, reload, queue, pool, quiet, loglevel, check, dev, stop, show, use_command_runner, without_gossip, without_mingle, without_heartbeat): # noqa: E501
138
141
  """Run a worker."""
139
142
 
140
143
  # Check Celery addon is installed
@@ -182,6 +185,9 @@ def worker(hostname, concurrency, reload, queue, pool, quiet, loglevel, check, d
182
185
  cmd += f' -P {pool}' if pool else ''
183
186
  cmd += f' -c {concurrency}' if concurrency else ''
184
187
  cmd += f' -l {loglevel}' if loglevel else ''
188
+ cmd += ' --without-mingle' if without_mingle else ''
189
+ cmd += ' --without-gossip' if without_gossip else ''
190
+ cmd += ' --without-heartbeat' if without_heartbeat else ''
185
191
 
186
192
  if reload:
187
193
  patterns = "celery.py;tasks/*.py;runners/*.py;serializers/*.py;output_types/*.py;hooks/*.py;exporters/*.py"
@@ -100,6 +100,7 @@ class Security(StrictModel):
100
100
  allow_local_file_access: bool = True
101
101
  auto_install_commands: bool = True
102
102
  force_source_install: bool = False
103
+ memory_limit_mb: int = -1
103
104
 
104
105
 
105
106
  class HTTP(StrictModel):
@@ -144,7 +145,7 @@ class Wordlists(StrictModel):
144
145
  templates: Dict[str, str] = {
145
146
  'bo0m_fuzz': 'https://raw.githubusercontent.com/Bo0oM/fuzz.txt/master/fuzz.txt',
146
147
  'combined_subdomains': 'https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/combined_subdomains.txt', # noqa: E501
147
- 'directory_list_small': 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Discovery/Web-Content/directory-list-2.3-small.txt', # noqa: E501
148
+ 'directory_list_small': 'https://gist.githubusercontent.com/sl4v/c087e36164e74233514b/raw/c51a811c70bbdd87f4725521420cc30e7232b36d/directory-list-2.3-small.txt', # noqa: E501
148
149
  }
149
150
  lists: Dict[str, List[str]] = {}
150
151
 
@@ -0,0 +1,24 @@
1
+ type: workflow
2
+ name: user_hunt
3
+ alias: userhunt
4
+ description: User account search
5
+ tags: [user_account]
6
+ input_types:
7
+ - slug
8
+ - string
9
+ - email
10
+
11
+ tasks:
12
+ _group/hunt_users:
13
+ maigret:
14
+ description: Hunt user accounts
15
+ targets_:
16
+ - type: target
17
+ field: name
18
+ condition: target.type != 'email'
19
+ h8mail:
20
+ description: Find password leaks
21
+ targets_:
22
+ - type: target
23
+ field: name
24
+ condition: target.type == 'email'
@@ -5,15 +5,28 @@ description: Wordpress vulnerability scan
5
5
  tags: [http, wordpress, vulnerability]
6
6
  input_types:
7
7
  - url
8
+ - ip
9
+ - host
10
+ - host:port
8
11
 
9
12
  tasks:
13
+ httpx:
14
+ description: URL probe
15
+ tech_detect: True
16
+
10
17
  _group/hunt_wordpress:
11
18
  nuclei:
12
19
  description: Nuclei Wordpress scan
13
20
  tags: [wordpress]
21
+ targets_:
22
+ - url.url
14
23
 
15
24
  wpscan:
16
25
  description: WPScan
26
+ targets_:
27
+ - url.url
17
28
 
18
29
  wpprobe:
19
30
  description: WPProbe
31
+ targets_:
32
+ - url.url
@@ -14,6 +14,16 @@ ITEMS_TO_SEND = {
14
14
  'url': ['screenshot_path', 'stored_response_path']
15
15
  }
16
16
 
17
+ _gcs_client = None
18
+
19
+
20
+ def get_gcs_client():
21
+ """Get or create GCS client"""
22
+ global _gcs_client
23
+ if _gcs_client is None:
24
+ _gcs_client = storage.Client()
25
+ return _gcs_client
26
+
17
27
 
18
28
  def process_item(self, item):
19
29
  if item._type not in ITEMS_TO_SEND.keys():
@@ -39,7 +49,7 @@ def process_item(self, item):
39
49
  def upload_blob(bucket_name, source_file_name, destination_blob_name):
40
50
  """Uploads a file to the bucket."""
41
51
  start_time = time()
42
- storage_client = storage.Client()
52
+ storage_client = get_gcs_client()
43
53
  bucket = storage_client.bucket(bucket_name)
44
54
  blob = bucket.blob(destination_blob_name)
45
55
  with open(source_file_name, 'rb') as f: