@etcsec-com/etc-collector 1.4.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 (617) hide show
  1. package/.env.example +60 -0
  2. package/.env.test.example +33 -0
  3. package/.github/workflows/ci.yml +83 -0
  4. package/.github/workflows/release.yml +246 -0
  5. package/.prettierrc.json +10 -0
  6. package/CHANGELOG.md +15 -0
  7. package/Dockerfile +57 -0
  8. package/LICENSE +190 -0
  9. package/README.md +194 -0
  10. package/dist/api/controllers/audit.controller.d.ts +21 -0
  11. package/dist/api/controllers/audit.controller.d.ts.map +1 -0
  12. package/dist/api/controllers/audit.controller.js +179 -0
  13. package/dist/api/controllers/audit.controller.js.map +1 -0
  14. package/dist/api/controllers/auth.controller.d.ts +16 -0
  15. package/dist/api/controllers/auth.controller.d.ts.map +1 -0
  16. package/dist/api/controllers/auth.controller.js +146 -0
  17. package/dist/api/controllers/auth.controller.js.map +1 -0
  18. package/dist/api/controllers/export.controller.d.ts +27 -0
  19. package/dist/api/controllers/export.controller.d.ts.map +1 -0
  20. package/dist/api/controllers/export.controller.js +80 -0
  21. package/dist/api/controllers/export.controller.js.map +1 -0
  22. package/dist/api/controllers/health.controller.d.ts +5 -0
  23. package/dist/api/controllers/health.controller.d.ts.map +1 -0
  24. package/dist/api/controllers/health.controller.js +16 -0
  25. package/dist/api/controllers/health.controller.js.map +1 -0
  26. package/dist/api/controllers/jobs.controller.d.ts +13 -0
  27. package/dist/api/controllers/jobs.controller.d.ts.map +1 -0
  28. package/dist/api/controllers/jobs.controller.js +125 -0
  29. package/dist/api/controllers/jobs.controller.js.map +1 -0
  30. package/dist/api/controllers/providers.controller.d.ts +15 -0
  31. package/dist/api/controllers/providers.controller.d.ts.map +1 -0
  32. package/dist/api/controllers/providers.controller.js +112 -0
  33. package/dist/api/controllers/providers.controller.js.map +1 -0
  34. package/dist/api/dto/AuditRequest.dto.d.ts +6 -0
  35. package/dist/api/dto/AuditRequest.dto.d.ts.map +1 -0
  36. package/dist/api/dto/AuditRequest.dto.js +3 -0
  37. package/dist/api/dto/AuditRequest.dto.js.map +1 -0
  38. package/dist/api/dto/AuditResponse.dto.d.ts +17 -0
  39. package/dist/api/dto/AuditResponse.dto.d.ts.map +1 -0
  40. package/dist/api/dto/AuditResponse.dto.js +3 -0
  41. package/dist/api/dto/AuditResponse.dto.js.map +1 -0
  42. package/dist/api/dto/TokenRequest.dto.d.ts +6 -0
  43. package/dist/api/dto/TokenRequest.dto.d.ts.map +1 -0
  44. package/dist/api/dto/TokenRequest.dto.js +3 -0
  45. package/dist/api/dto/TokenRequest.dto.js.map +1 -0
  46. package/dist/api/dto/TokenResponse.dto.d.ts +12 -0
  47. package/dist/api/dto/TokenResponse.dto.d.ts.map +1 -0
  48. package/dist/api/dto/TokenResponse.dto.js +3 -0
  49. package/dist/api/dto/TokenResponse.dto.js.map +1 -0
  50. package/dist/api/middlewares/authenticate.d.ts +12 -0
  51. package/dist/api/middlewares/authenticate.d.ts.map +1 -0
  52. package/dist/api/middlewares/authenticate.js +141 -0
  53. package/dist/api/middlewares/authenticate.js.map +1 -0
  54. package/dist/api/middlewares/errorHandler.d.ts +3 -0
  55. package/dist/api/middlewares/errorHandler.d.ts.map +1 -0
  56. package/dist/api/middlewares/errorHandler.js +30 -0
  57. package/dist/api/middlewares/errorHandler.js.map +1 -0
  58. package/dist/api/middlewares/rateLimit.d.ts +3 -0
  59. package/dist/api/middlewares/rateLimit.d.ts.map +1 -0
  60. package/dist/api/middlewares/rateLimit.js +34 -0
  61. package/dist/api/middlewares/rateLimit.js.map +1 -0
  62. package/dist/api/middlewares/validate.d.ts +4 -0
  63. package/dist/api/middlewares/validate.d.ts.map +1 -0
  64. package/dist/api/middlewares/validate.js +31 -0
  65. package/dist/api/middlewares/validate.js.map +1 -0
  66. package/dist/api/routes/audit.routes.d.ts +5 -0
  67. package/dist/api/routes/audit.routes.d.ts.map +1 -0
  68. package/dist/api/routes/audit.routes.js +24 -0
  69. package/dist/api/routes/audit.routes.js.map +1 -0
  70. package/dist/api/routes/auth.routes.d.ts +6 -0
  71. package/dist/api/routes/auth.routes.d.ts.map +1 -0
  72. package/dist/api/routes/auth.routes.js +22 -0
  73. package/dist/api/routes/auth.routes.js.map +1 -0
  74. package/dist/api/routes/export.routes.d.ts +5 -0
  75. package/dist/api/routes/export.routes.d.ts.map +1 -0
  76. package/dist/api/routes/export.routes.js +16 -0
  77. package/dist/api/routes/export.routes.js.map +1 -0
  78. package/dist/api/routes/health.routes.d.ts +4 -0
  79. package/dist/api/routes/health.routes.d.ts.map +1 -0
  80. package/dist/api/routes/health.routes.js +11 -0
  81. package/dist/api/routes/health.routes.js.map +1 -0
  82. package/dist/api/routes/index.d.ts +10 -0
  83. package/dist/api/routes/index.d.ts.map +1 -0
  84. package/dist/api/routes/index.js +20 -0
  85. package/dist/api/routes/index.js.map +1 -0
  86. package/dist/api/routes/providers.routes.d.ts +5 -0
  87. package/dist/api/routes/providers.routes.d.ts.map +1 -0
  88. package/dist/api/routes/providers.routes.js +13 -0
  89. package/dist/api/routes/providers.routes.js.map +1 -0
  90. package/dist/api/validators/audit.schemas.d.ts +60 -0
  91. package/dist/api/validators/audit.schemas.d.ts.map +1 -0
  92. package/dist/api/validators/audit.schemas.js +55 -0
  93. package/dist/api/validators/audit.schemas.js.map +1 -0
  94. package/dist/api/validators/auth.schemas.d.ts +17 -0
  95. package/dist/api/validators/auth.schemas.d.ts.map +1 -0
  96. package/dist/api/validators/auth.schemas.js +21 -0
  97. package/dist/api/validators/auth.schemas.js.map +1 -0
  98. package/dist/app.d.ts +3 -0
  99. package/dist/app.d.ts.map +1 -0
  100. package/dist/app.js +62 -0
  101. package/dist/app.js.map +1 -0
  102. package/dist/config/config.schema.d.ts +65 -0
  103. package/dist/config/config.schema.d.ts.map +1 -0
  104. package/dist/config/config.schema.js +95 -0
  105. package/dist/config/config.schema.js.map +1 -0
  106. package/dist/config/index.d.ts +4 -0
  107. package/dist/config/index.d.ts.map +1 -0
  108. package/dist/config/index.js +75 -0
  109. package/dist/config/index.js.map +1 -0
  110. package/dist/container.d.ts +47 -0
  111. package/dist/container.d.ts.map +1 -0
  112. package/dist/container.js +137 -0
  113. package/dist/container.js.map +1 -0
  114. package/dist/data/database.d.ts +13 -0
  115. package/dist/data/database.d.ts.map +1 -0
  116. package/dist/data/database.js +68 -0
  117. package/dist/data/database.js.map +1 -0
  118. package/dist/data/jobs/token-cleanup.job.d.ts +23 -0
  119. package/dist/data/jobs/token-cleanup.job.d.ts.map +1 -0
  120. package/dist/data/jobs/token-cleanup.job.js +96 -0
  121. package/dist/data/jobs/token-cleanup.job.js.map +1 -0
  122. package/dist/data/migrations/migration.runner.d.ts +13 -0
  123. package/dist/data/migrations/migration.runner.d.ts.map +1 -0
  124. package/dist/data/migrations/migration.runner.js +136 -0
  125. package/dist/data/migrations/migration.runner.js.map +1 -0
  126. package/dist/data/models/Token.model.d.ts +30 -0
  127. package/dist/data/models/Token.model.d.ts.map +1 -0
  128. package/dist/data/models/Token.model.js +3 -0
  129. package/dist/data/models/Token.model.js.map +1 -0
  130. package/dist/data/repositories/token.repository.d.ts +16 -0
  131. package/dist/data/repositories/token.repository.d.ts.map +1 -0
  132. package/dist/data/repositories/token.repository.js +97 -0
  133. package/dist/data/repositories/token.repository.js.map +1 -0
  134. package/dist/providers/azure/auth.provider.d.ts +5 -0
  135. package/dist/providers/azure/auth.provider.d.ts.map +1 -0
  136. package/dist/providers/azure/auth.provider.js +13 -0
  137. package/dist/providers/azure/auth.provider.js.map +1 -0
  138. package/dist/providers/azure/azure-errors.d.ts +40 -0
  139. package/dist/providers/azure/azure-errors.d.ts.map +1 -0
  140. package/dist/providers/azure/azure-errors.js +121 -0
  141. package/dist/providers/azure/azure-errors.js.map +1 -0
  142. package/dist/providers/azure/azure-retry.d.ts +41 -0
  143. package/dist/providers/azure/azure-retry.d.ts.map +1 -0
  144. package/dist/providers/azure/azure-retry.js +85 -0
  145. package/dist/providers/azure/azure-retry.js.map +1 -0
  146. package/dist/providers/azure/graph-client.d.ts +26 -0
  147. package/dist/providers/azure/graph-client.d.ts.map +1 -0
  148. package/dist/providers/azure/graph-client.js +146 -0
  149. package/dist/providers/azure/graph-client.js.map +1 -0
  150. package/dist/providers/azure/graph.provider.d.ts +23 -0
  151. package/dist/providers/azure/graph.provider.d.ts.map +1 -0
  152. package/dist/providers/azure/graph.provider.js +161 -0
  153. package/dist/providers/azure/graph.provider.js.map +1 -0
  154. package/dist/providers/azure/queries/app.queries.d.ts +6 -0
  155. package/dist/providers/azure/queries/app.queries.d.ts.map +1 -0
  156. package/dist/providers/azure/queries/app.queries.js +9 -0
  157. package/dist/providers/azure/queries/app.queries.js.map +1 -0
  158. package/dist/providers/azure/queries/policy.queries.d.ts +6 -0
  159. package/dist/providers/azure/queries/policy.queries.d.ts.map +1 -0
  160. package/dist/providers/azure/queries/policy.queries.js +9 -0
  161. package/dist/providers/azure/queries/policy.queries.js.map +1 -0
  162. package/dist/providers/azure/queries/user.queries.d.ts +7 -0
  163. package/dist/providers/azure/queries/user.queries.d.ts.map +1 -0
  164. package/dist/providers/azure/queries/user.queries.js +10 -0
  165. package/dist/providers/azure/queries/user.queries.js.map +1 -0
  166. package/dist/providers/interfaces/IGraphProvider.d.ts +31 -0
  167. package/dist/providers/interfaces/IGraphProvider.d.ts.map +1 -0
  168. package/dist/providers/interfaces/IGraphProvider.js +3 -0
  169. package/dist/providers/interfaces/IGraphProvider.js.map +1 -0
  170. package/dist/providers/interfaces/ILDAPProvider.d.ts +37 -0
  171. package/dist/providers/interfaces/ILDAPProvider.d.ts.map +1 -0
  172. package/dist/providers/interfaces/ILDAPProvider.js +3 -0
  173. package/dist/providers/interfaces/ILDAPProvider.js.map +1 -0
  174. package/dist/providers/ldap/acl-parser.d.ts +8 -0
  175. package/dist/providers/ldap/acl-parser.d.ts.map +1 -0
  176. package/dist/providers/ldap/acl-parser.js +157 -0
  177. package/dist/providers/ldap/acl-parser.js.map +1 -0
  178. package/dist/providers/ldap/ad-mappers.d.ts +8 -0
  179. package/dist/providers/ldap/ad-mappers.d.ts.map +1 -0
  180. package/dist/providers/ldap/ad-mappers.js +162 -0
  181. package/dist/providers/ldap/ad-mappers.js.map +1 -0
  182. package/dist/providers/ldap/ldap-client.d.ts +33 -0
  183. package/dist/providers/ldap/ldap-client.d.ts.map +1 -0
  184. package/dist/providers/ldap/ldap-client.js +195 -0
  185. package/dist/providers/ldap/ldap-client.js.map +1 -0
  186. package/dist/providers/ldap/ldap-errors.d.ts +48 -0
  187. package/dist/providers/ldap/ldap-errors.d.ts.map +1 -0
  188. package/dist/providers/ldap/ldap-errors.js +120 -0
  189. package/dist/providers/ldap/ldap-errors.js.map +1 -0
  190. package/dist/providers/ldap/ldap-retry.d.ts +14 -0
  191. package/dist/providers/ldap/ldap-retry.d.ts.map +1 -0
  192. package/dist/providers/ldap/ldap-retry.js +102 -0
  193. package/dist/providers/ldap/ldap-retry.js.map +1 -0
  194. package/dist/providers/ldap/ldap-sanitizer.d.ts +12 -0
  195. package/dist/providers/ldap/ldap-sanitizer.d.ts.map +1 -0
  196. package/dist/providers/ldap/ldap-sanitizer.js +104 -0
  197. package/dist/providers/ldap/ldap-sanitizer.js.map +1 -0
  198. package/dist/providers/ldap/ldap.provider.d.ts +21 -0
  199. package/dist/providers/ldap/ldap.provider.d.ts.map +1 -0
  200. package/dist/providers/ldap/ldap.provider.js +165 -0
  201. package/dist/providers/ldap/ldap.provider.js.map +1 -0
  202. package/dist/providers/ldap/queries/computer.queries.d.ts +6 -0
  203. package/dist/providers/ldap/queries/computer.queries.d.ts.map +1 -0
  204. package/dist/providers/ldap/queries/computer.queries.js +9 -0
  205. package/dist/providers/ldap/queries/computer.queries.js.map +1 -0
  206. package/dist/providers/ldap/queries/group.queries.d.ts +6 -0
  207. package/dist/providers/ldap/queries/group.queries.d.ts.map +1 -0
  208. package/dist/providers/ldap/queries/group.queries.js +9 -0
  209. package/dist/providers/ldap/queries/group.queries.js.map +1 -0
  210. package/dist/providers/ldap/queries/user.queries.d.ts +7 -0
  211. package/dist/providers/ldap/queries/user.queries.d.ts.map +1 -0
  212. package/dist/providers/ldap/queries/user.queries.js +10 -0
  213. package/dist/providers/ldap/queries/user.queries.js.map +1 -0
  214. package/dist/providers/smb/smb.provider.d.ts +68 -0
  215. package/dist/providers/smb/smb.provider.d.ts.map +1 -0
  216. package/dist/providers/smb/smb.provider.js +382 -0
  217. package/dist/providers/smb/smb.provider.js.map +1 -0
  218. package/dist/server.d.ts +2 -0
  219. package/dist/server.d.ts.map +1 -0
  220. package/dist/server.js +44 -0
  221. package/dist/server.js.map +1 -0
  222. package/dist/services/audit/ad-audit.service.d.ts +70 -0
  223. package/dist/services/audit/ad-audit.service.d.ts.map +1 -0
  224. package/dist/services/audit/ad-audit.service.js +1019 -0
  225. package/dist/services/audit/ad-audit.service.js.map +1 -0
  226. package/dist/services/audit/attack-graph.service.d.ts +62 -0
  227. package/dist/services/audit/attack-graph.service.d.ts.map +1 -0
  228. package/dist/services/audit/attack-graph.service.js +702 -0
  229. package/dist/services/audit/attack-graph.service.js.map +1 -0
  230. package/dist/services/audit/audit.service.d.ts +4 -0
  231. package/dist/services/audit/audit.service.d.ts.map +1 -0
  232. package/dist/services/audit/audit.service.js +10 -0
  233. package/dist/services/audit/audit.service.js.map +1 -0
  234. package/dist/services/audit/azure-audit.service.d.ts +37 -0
  235. package/dist/services/audit/azure-audit.service.d.ts.map +1 -0
  236. package/dist/services/audit/azure-audit.service.js +153 -0
  237. package/dist/services/audit/azure-audit.service.js.map +1 -0
  238. package/dist/services/audit/detectors/ad/accounts.detector.d.ts +37 -0
  239. package/dist/services/audit/detectors/ad/accounts.detector.d.ts.map +1 -0
  240. package/dist/services/audit/detectors/ad/accounts.detector.js +881 -0
  241. package/dist/services/audit/detectors/ad/accounts.detector.js.map +1 -0
  242. package/dist/services/audit/detectors/ad/adcs.detector.d.ts +21 -0
  243. package/dist/services/audit/detectors/ad/adcs.detector.d.ts.map +1 -0
  244. package/dist/services/audit/detectors/ad/adcs.detector.js +227 -0
  245. package/dist/services/audit/detectors/ad/adcs.detector.js.map +1 -0
  246. package/dist/services/audit/detectors/ad/advanced.detector.d.ts +63 -0
  247. package/dist/services/audit/detectors/ad/advanced.detector.d.ts.map +1 -0
  248. package/dist/services/audit/detectors/ad/advanced.detector.js +867 -0
  249. package/dist/services/audit/detectors/ad/advanced.detector.js.map +1 -0
  250. package/dist/services/audit/detectors/ad/attack-paths.detector.d.ts +16 -0
  251. package/dist/services/audit/detectors/ad/attack-paths.detector.d.ts.map +1 -0
  252. package/dist/services/audit/detectors/ad/attack-paths.detector.js +369 -0
  253. package/dist/services/audit/detectors/ad/attack-paths.detector.js.map +1 -0
  254. package/dist/services/audit/detectors/ad/compliance.detector.d.ts +28 -0
  255. package/dist/services/audit/detectors/ad/compliance.detector.d.ts.map +1 -0
  256. package/dist/services/audit/detectors/ad/compliance.detector.js +896 -0
  257. package/dist/services/audit/detectors/ad/compliance.detector.js.map +1 -0
  258. package/dist/services/audit/detectors/ad/computers.detector.d.ts +30 -0
  259. package/dist/services/audit/detectors/ad/computers.detector.d.ts.map +1 -0
  260. package/dist/services/audit/detectors/ad/computers.detector.js +799 -0
  261. package/dist/services/audit/detectors/ad/computers.detector.js.map +1 -0
  262. package/dist/services/audit/detectors/ad/gpo.detector.d.ts +17 -0
  263. package/dist/services/audit/detectors/ad/gpo.detector.d.ts.map +1 -0
  264. package/dist/services/audit/detectors/ad/gpo.detector.js +257 -0
  265. package/dist/services/audit/detectors/ad/gpo.detector.js.map +1 -0
  266. package/dist/services/audit/detectors/ad/groups.detector.d.ts +19 -0
  267. package/dist/services/audit/detectors/ad/groups.detector.d.ts.map +1 -0
  268. package/dist/services/audit/detectors/ad/groups.detector.js +488 -0
  269. package/dist/services/audit/detectors/ad/groups.detector.js.map +1 -0
  270. package/dist/services/audit/detectors/ad/index.d.ts +15 -0
  271. package/dist/services/audit/detectors/ad/index.d.ts.map +1 -0
  272. package/dist/services/audit/detectors/ad/index.js +51 -0
  273. package/dist/services/audit/detectors/ad/index.js.map +1 -0
  274. package/dist/services/audit/detectors/ad/kerberos.detector.d.ts +17 -0
  275. package/dist/services/audit/detectors/ad/kerberos.detector.d.ts.map +1 -0
  276. package/dist/services/audit/detectors/ad/kerberos.detector.js +293 -0
  277. package/dist/services/audit/detectors/ad/kerberos.detector.js.map +1 -0
  278. package/dist/services/audit/detectors/ad/monitoring.detector.d.ts +23 -0
  279. package/dist/services/audit/detectors/ad/monitoring.detector.d.ts.map +1 -0
  280. package/dist/services/audit/detectors/ad/monitoring.detector.js +328 -0
  281. package/dist/services/audit/detectors/ad/monitoring.detector.js.map +1 -0
  282. package/dist/services/audit/detectors/ad/network.detector.d.ts +39 -0
  283. package/dist/services/audit/detectors/ad/network.detector.d.ts.map +1 -0
  284. package/dist/services/audit/detectors/ad/network.detector.js +257 -0
  285. package/dist/services/audit/detectors/ad/network.detector.js.map +1 -0
  286. package/dist/services/audit/detectors/ad/password.detector.d.ts +14 -0
  287. package/dist/services/audit/detectors/ad/password.detector.d.ts.map +1 -0
  288. package/dist/services/audit/detectors/ad/password.detector.js +235 -0
  289. package/dist/services/audit/detectors/ad/password.detector.js.map +1 -0
  290. package/dist/services/audit/detectors/ad/permissions.detector.d.ts +20 -0
  291. package/dist/services/audit/detectors/ad/permissions.detector.d.ts.map +1 -0
  292. package/dist/services/audit/detectors/ad/permissions.detector.js +392 -0
  293. package/dist/services/audit/detectors/ad/permissions.detector.js.map +1 -0
  294. package/dist/services/audit/detectors/ad/trusts.detector.d.ts +11 -0
  295. package/dist/services/audit/detectors/ad/trusts.detector.d.ts.map +1 -0
  296. package/dist/services/audit/detectors/ad/trusts.detector.js +186 -0
  297. package/dist/services/audit/detectors/ad/trusts.detector.js.map +1 -0
  298. package/dist/services/audit/detectors/azure/app-security.detector.d.ts +11 -0
  299. package/dist/services/audit/detectors/azure/app-security.detector.d.ts.map +1 -0
  300. package/dist/services/audit/detectors/azure/app-security.detector.js +184 -0
  301. package/dist/services/audit/detectors/azure/app-security.detector.js.map +1 -0
  302. package/dist/services/audit/detectors/azure/conditional-access.detector.d.ts +10 -0
  303. package/dist/services/audit/detectors/azure/conditional-access.detector.d.ts.map +1 -0
  304. package/dist/services/audit/detectors/azure/conditional-access.detector.js +130 -0
  305. package/dist/services/audit/detectors/azure/conditional-access.detector.js.map +1 -0
  306. package/dist/services/audit/detectors/azure/privilege-security.detector.d.ts +8 -0
  307. package/dist/services/audit/detectors/azure/privilege-security.detector.d.ts.map +1 -0
  308. package/dist/services/audit/detectors/azure/privilege-security.detector.js +113 -0
  309. package/dist/services/audit/detectors/azure/privilege-security.detector.js.map +1 -0
  310. package/dist/services/audit/detectors/azure/user-security.detector.d.ts +14 -0
  311. package/dist/services/audit/detectors/azure/user-security.detector.d.ts.map +1 -0
  312. package/dist/services/audit/detectors/azure/user-security.detector.js +198 -0
  313. package/dist/services/audit/detectors/azure/user-security.detector.js.map +1 -0
  314. package/dist/services/audit/detectors/index.d.ts +2 -0
  315. package/dist/services/audit/detectors/index.d.ts.map +1 -0
  316. package/dist/services/audit/detectors/index.js +38 -0
  317. package/dist/services/audit/detectors/index.js.map +1 -0
  318. package/dist/services/audit/response-formatter.d.ts +176 -0
  319. package/dist/services/audit/response-formatter.d.ts.map +1 -0
  320. package/dist/services/audit/response-formatter.js +240 -0
  321. package/dist/services/audit/response-formatter.js.map +1 -0
  322. package/dist/services/audit/scoring.service.d.ts +15 -0
  323. package/dist/services/audit/scoring.service.d.ts.map +1 -0
  324. package/dist/services/audit/scoring.service.js +139 -0
  325. package/dist/services/audit/scoring.service.js.map +1 -0
  326. package/dist/services/auth/crypto.service.d.ts +19 -0
  327. package/dist/services/auth/crypto.service.d.ts.map +1 -0
  328. package/dist/services/auth/crypto.service.js +135 -0
  329. package/dist/services/auth/crypto.service.js.map +1 -0
  330. package/dist/services/auth/errors.d.ts +19 -0
  331. package/dist/services/auth/errors.d.ts.map +1 -0
  332. package/dist/services/auth/errors.js +46 -0
  333. package/dist/services/auth/errors.js.map +1 -0
  334. package/dist/services/auth/token.service.d.ts +41 -0
  335. package/dist/services/auth/token.service.d.ts.map +1 -0
  336. package/dist/services/auth/token.service.js +208 -0
  337. package/dist/services/auth/token.service.js.map +1 -0
  338. package/dist/services/config/config.service.d.ts +6 -0
  339. package/dist/services/config/config.service.d.ts.map +1 -0
  340. package/dist/services/config/config.service.js +64 -0
  341. package/dist/services/config/config.service.js.map +1 -0
  342. package/dist/services/export/export.service.d.ts +28 -0
  343. package/dist/services/export/export.service.d.ts.map +1 -0
  344. package/dist/services/export/export.service.js +28 -0
  345. package/dist/services/export/export.service.js.map +1 -0
  346. package/dist/services/export/formatters/csv.formatter.d.ts +8 -0
  347. package/dist/services/export/formatters/csv.formatter.d.ts.map +1 -0
  348. package/dist/services/export/formatters/csv.formatter.js +46 -0
  349. package/dist/services/export/formatters/csv.formatter.js.map +1 -0
  350. package/dist/services/export/formatters/json.formatter.d.ts +40 -0
  351. package/dist/services/export/formatters/json.formatter.d.ts.map +1 -0
  352. package/dist/services/export/formatters/json.formatter.js +58 -0
  353. package/dist/services/export/formatters/json.formatter.js.map +1 -0
  354. package/dist/services/jobs/azure-job-runner.d.ts +38 -0
  355. package/dist/services/jobs/azure-job-runner.d.ts.map +1 -0
  356. package/dist/services/jobs/azure-job-runner.js +199 -0
  357. package/dist/services/jobs/azure-job-runner.js.map +1 -0
  358. package/dist/services/jobs/index.d.ts +4 -0
  359. package/dist/services/jobs/index.d.ts.map +1 -0
  360. package/dist/services/jobs/index.js +20 -0
  361. package/dist/services/jobs/index.js.map +1 -0
  362. package/dist/services/jobs/job-runner.d.ts +64 -0
  363. package/dist/services/jobs/job-runner.d.ts.map +1 -0
  364. package/dist/services/jobs/job-runner.js +952 -0
  365. package/dist/services/jobs/job-runner.js.map +1 -0
  366. package/dist/services/jobs/job-store.d.ts +27 -0
  367. package/dist/services/jobs/job-store.d.ts.map +1 -0
  368. package/dist/services/jobs/job-store.js +261 -0
  369. package/dist/services/jobs/job-store.js.map +1 -0
  370. package/dist/services/jobs/job.types.d.ts +67 -0
  371. package/dist/services/jobs/job.types.d.ts.map +1 -0
  372. package/dist/services/jobs/job.types.js +36 -0
  373. package/dist/services/jobs/job.types.js.map +1 -0
  374. package/dist/types/ad.types.d.ts +74 -0
  375. package/dist/types/ad.types.d.ts.map +1 -0
  376. package/dist/types/ad.types.js +3 -0
  377. package/dist/types/ad.types.js.map +1 -0
  378. package/dist/types/adcs.types.d.ts +58 -0
  379. package/dist/types/adcs.types.d.ts.map +1 -0
  380. package/dist/types/adcs.types.js +38 -0
  381. package/dist/types/adcs.types.js.map +1 -0
  382. package/dist/types/attack-graph.types.d.ts +135 -0
  383. package/dist/types/attack-graph.types.d.ts.map +1 -0
  384. package/dist/types/attack-graph.types.js +58 -0
  385. package/dist/types/attack-graph.types.js.map +1 -0
  386. package/dist/types/audit.types.d.ts +34 -0
  387. package/dist/types/audit.types.d.ts.map +1 -0
  388. package/dist/types/audit.types.js +3 -0
  389. package/dist/types/audit.types.js.map +1 -0
  390. package/dist/types/azure.types.d.ts +61 -0
  391. package/dist/types/azure.types.d.ts.map +1 -0
  392. package/dist/types/azure.types.js +3 -0
  393. package/dist/types/azure.types.js.map +1 -0
  394. package/dist/types/config.types.d.ts +63 -0
  395. package/dist/types/config.types.d.ts.map +1 -0
  396. package/dist/types/config.types.js +3 -0
  397. package/dist/types/config.types.js.map +1 -0
  398. package/dist/types/error.types.d.ts +33 -0
  399. package/dist/types/error.types.d.ts.map +1 -0
  400. package/dist/types/error.types.js +70 -0
  401. package/dist/types/error.types.js.map +1 -0
  402. package/dist/types/finding.types.d.ts +133 -0
  403. package/dist/types/finding.types.d.ts.map +1 -0
  404. package/dist/types/finding.types.js +3 -0
  405. package/dist/types/finding.types.js.map +1 -0
  406. package/dist/types/gpo.types.d.ts +39 -0
  407. package/dist/types/gpo.types.d.ts.map +1 -0
  408. package/dist/types/gpo.types.js +15 -0
  409. package/dist/types/gpo.types.js.map +1 -0
  410. package/dist/types/token.types.d.ts +26 -0
  411. package/dist/types/token.types.d.ts.map +1 -0
  412. package/dist/types/token.types.js +3 -0
  413. package/dist/types/token.types.js.map +1 -0
  414. package/dist/types/trust.types.d.ts +45 -0
  415. package/dist/types/trust.types.d.ts.map +1 -0
  416. package/dist/types/trust.types.js +71 -0
  417. package/dist/types/trust.types.js.map +1 -0
  418. package/dist/utils/entity-converter.d.ts +17 -0
  419. package/dist/utils/entity-converter.d.ts.map +1 -0
  420. package/dist/utils/entity-converter.js +285 -0
  421. package/dist/utils/entity-converter.js.map +1 -0
  422. package/dist/utils/graph.util.d.ts +66 -0
  423. package/dist/utils/graph.util.d.ts.map +1 -0
  424. package/dist/utils/graph.util.js +382 -0
  425. package/dist/utils/graph.util.js.map +1 -0
  426. package/dist/utils/logger.d.ts +7 -0
  427. package/dist/utils/logger.d.ts.map +1 -0
  428. package/dist/utils/logger.js +86 -0
  429. package/dist/utils/logger.js.map +1 -0
  430. package/dist/utils/type-name-normalizer.d.ts +5 -0
  431. package/dist/utils/type-name-normalizer.d.ts.map +1 -0
  432. package/dist/utils/type-name-normalizer.js +218 -0
  433. package/dist/utils/type-name-normalizer.js.map +1 -0
  434. package/docker-compose.yml +26 -0
  435. package/docs/api/README.md +178 -0
  436. package/docs/api/openapi.yaml +1524 -0
  437. package/eslint.config.js +54 -0
  438. package/jest.config.js +38 -0
  439. package/package.json +97 -0
  440. package/scripts/fetch-ad-cert.sh +142 -0
  441. package/src/.gitkeep +0 -0
  442. package/src/api/.gitkeep +0 -0
  443. package/src/api/controllers/.gitkeep +0 -0
  444. package/src/api/controllers/audit.controller.ts +313 -0
  445. package/src/api/controllers/auth.controller.ts +258 -0
  446. package/src/api/controllers/export.controller.ts +153 -0
  447. package/src/api/controllers/health.controller.ts +16 -0
  448. package/src/api/controllers/jobs.controller.ts +187 -0
  449. package/src/api/controllers/providers.controller.ts +165 -0
  450. package/src/api/dto/.gitkeep +0 -0
  451. package/src/api/dto/AuditRequest.dto.ts +8 -0
  452. package/src/api/dto/AuditResponse.dto.ts +19 -0
  453. package/src/api/dto/TokenRequest.dto.ts +8 -0
  454. package/src/api/dto/TokenResponse.dto.ts +14 -0
  455. package/src/api/middlewares/.gitkeep +0 -0
  456. package/src/api/middlewares/authenticate.ts +203 -0
  457. package/src/api/middlewares/errorHandler.ts +54 -0
  458. package/src/api/middlewares/rateLimit.ts +35 -0
  459. package/src/api/middlewares/validate.ts +32 -0
  460. package/src/api/routes/.gitkeep +0 -0
  461. package/src/api/routes/audit.routes.ts +77 -0
  462. package/src/api/routes/auth.routes.ts +71 -0
  463. package/src/api/routes/export.routes.ts +34 -0
  464. package/src/api/routes/health.routes.ts +14 -0
  465. package/src/api/routes/index.ts +40 -0
  466. package/src/api/routes/providers.routes.ts +24 -0
  467. package/src/api/validators/.gitkeep +0 -0
  468. package/src/api/validators/audit.schemas.ts +59 -0
  469. package/src/api/validators/auth.schemas.ts +59 -0
  470. package/src/app.ts +87 -0
  471. package/src/config/.gitkeep +0 -0
  472. package/src/config/config.schema.ts +108 -0
  473. package/src/config/index.ts +82 -0
  474. package/src/container.ts +221 -0
  475. package/src/data/.gitkeep +0 -0
  476. package/src/data/database.ts +78 -0
  477. package/src/data/jobs/token-cleanup.job.ts +166 -0
  478. package/src/data/migrations/.gitkeep +0 -0
  479. package/src/data/migrations/001_initial_schema.sql +47 -0
  480. package/src/data/migrations/migration.runner.ts +125 -0
  481. package/src/data/models/.gitkeep +0 -0
  482. package/src/data/models/Token.model.ts +35 -0
  483. package/src/data/repositories/.gitkeep +0 -0
  484. package/src/data/repositories/token.repository.ts +160 -0
  485. package/src/providers/.gitkeep +0 -0
  486. package/src/providers/azure/.gitkeep +0 -0
  487. package/src/providers/azure/auth.provider.ts +14 -0
  488. package/src/providers/azure/azure-errors.ts +189 -0
  489. package/src/providers/azure/azure-retry.ts +168 -0
  490. package/src/providers/azure/graph-client.ts +315 -0
  491. package/src/providers/azure/graph.provider.ts +294 -0
  492. package/src/providers/azure/queries/app.queries.ts +9 -0
  493. package/src/providers/azure/queries/policy.queries.ts +9 -0
  494. package/src/providers/azure/queries/user.queries.ts +10 -0
  495. package/src/providers/interfaces/.gitkeep +0 -0
  496. package/src/providers/interfaces/IGraphProvider.ts +117 -0
  497. package/src/providers/interfaces/ILDAPProvider.ts +142 -0
  498. package/src/providers/ldap/.gitkeep +0 -0
  499. package/src/providers/ldap/acl-parser.ts +231 -0
  500. package/src/providers/ldap/ad-mappers.ts +280 -0
  501. package/src/providers/ldap/ldap-client.ts +259 -0
  502. package/src/providers/ldap/ldap-errors.ts +188 -0
  503. package/src/providers/ldap/ldap-retry.ts +267 -0
  504. package/src/providers/ldap/ldap-sanitizer.ts +273 -0
  505. package/src/providers/ldap/ldap.provider.ts +293 -0
  506. package/src/providers/ldap/queries/computer.queries.ts +9 -0
  507. package/src/providers/ldap/queries/group.queries.ts +9 -0
  508. package/src/providers/ldap/queries/user.queries.ts +10 -0
  509. package/src/providers/smb/smb.provider.ts +653 -0
  510. package/src/server.ts +60 -0
  511. package/src/services/.gitkeep +0 -0
  512. package/src/services/audit/.gitkeep +0 -0
  513. package/src/services/audit/ad-audit.service.ts +1481 -0
  514. package/src/services/audit/attack-graph.service.ts +1104 -0
  515. package/src/services/audit/audit.service.ts +12 -0
  516. package/src/services/audit/azure-audit.service.ts +286 -0
  517. package/src/services/audit/detectors/ad/accounts.detector.ts +1232 -0
  518. package/src/services/audit/detectors/ad/adcs.detector.ts +449 -0
  519. package/src/services/audit/detectors/ad/advanced.detector.ts +1270 -0
  520. package/src/services/audit/detectors/ad/attack-paths.detector.ts +600 -0
  521. package/src/services/audit/detectors/ad/compliance.detector.ts +1421 -0
  522. package/src/services/audit/detectors/ad/computers.detector.ts +1188 -0
  523. package/src/services/audit/detectors/ad/gpo.detector.ts +485 -0
  524. package/src/services/audit/detectors/ad/groups.detector.ts +685 -0
  525. package/src/services/audit/detectors/ad/index.ts +84 -0
  526. package/src/services/audit/detectors/ad/kerberos.detector.ts +424 -0
  527. package/src/services/audit/detectors/ad/monitoring.detector.ts +501 -0
  528. package/src/services/audit/detectors/ad/network.detector.ts +538 -0
  529. package/src/services/audit/detectors/ad/password.detector.ts +324 -0
  530. package/src/services/audit/detectors/ad/permissions.detector.ts +637 -0
  531. package/src/services/audit/detectors/ad/trusts.detector.ts +315 -0
  532. package/src/services/audit/detectors/azure/app-security.detector.ts +246 -0
  533. package/src/services/audit/detectors/azure/conditional-access.detector.ts +186 -0
  534. package/src/services/audit/detectors/azure/privilege-security.detector.ts +176 -0
  535. package/src/services/audit/detectors/azure/user-security.detector.ts +280 -0
  536. package/src/services/audit/detectors/index.ts +18 -0
  537. package/src/services/audit/response-formatter.ts +604 -0
  538. package/src/services/audit/scoring.service.ts +234 -0
  539. package/src/services/auth/.gitkeep +0 -0
  540. package/src/services/auth/crypto.service.ts +230 -0
  541. package/src/services/auth/errors.ts +47 -0
  542. package/src/services/auth/token.service.ts +420 -0
  543. package/src/services/config/.gitkeep +0 -0
  544. package/src/services/config/config.service.ts +75 -0
  545. package/src/services/export/.gitkeep +0 -0
  546. package/src/services/export/export.service.ts +99 -0
  547. package/src/services/export/formatters/csv.formatter.ts +124 -0
  548. package/src/services/export/formatters/json.formatter.ts +160 -0
  549. package/src/services/jobs/azure-job-runner.ts +312 -0
  550. package/src/services/jobs/index.ts +9 -0
  551. package/src/services/jobs/job-runner.ts +1280 -0
  552. package/src/services/jobs/job-store.ts +384 -0
  553. package/src/services/jobs/job.types.ts +182 -0
  554. package/src/types/.gitkeep +0 -0
  555. package/src/types/ad.types.ts +91 -0
  556. package/src/types/adcs.types.ts +107 -0
  557. package/src/types/attack-graph.types.ts +260 -0
  558. package/src/types/audit.types.ts +42 -0
  559. package/src/types/azure.types.ts +68 -0
  560. package/src/types/config.types.ts +79 -0
  561. package/src/types/error.types.ts +69 -0
  562. package/src/types/finding.types.ts +284 -0
  563. package/src/types/gpo.types.ts +72 -0
  564. package/src/types/smb2.d.ts +73 -0
  565. package/src/types/token.types.ts +32 -0
  566. package/src/types/trust.types.ts +140 -0
  567. package/src/utils/.gitkeep +0 -0
  568. package/src/utils/entity-converter.ts +453 -0
  569. package/src/utils/graph.util.ts +609 -0
  570. package/src/utils/logger.ts +111 -0
  571. package/src/utils/type-name-normalizer.ts +302 -0
  572. package/tests/.gitkeep +0 -0
  573. package/tests/e2e/.gitkeep +0 -0
  574. package/tests/fixtures/.gitkeep +0 -0
  575. package/tests/integration/.gitkeep +0 -0
  576. package/tests/integration/README.md +156 -0
  577. package/tests/integration/ad-audit.integration.test.ts +216 -0
  578. package/tests/integration/api/.gitkeep +0 -0
  579. package/tests/integration/api/endpoints.integration.test.ts +431 -0
  580. package/tests/integration/auth/jwt-authentication.integration.test.ts +358 -0
  581. package/tests/integration/providers/.gitkeep +0 -0
  582. package/tests/integration/providers/azure-basic.integration.test.ts +167 -0
  583. package/tests/integration/providers/ldap-basic.integration.test.ts +152 -0
  584. package/tests/integration/providers/ldap-connectivity.test.ts +44 -0
  585. package/tests/integration/providers/ldap-provider.integration.test.ts +347 -0
  586. package/tests/mocks/.gitkeep +0 -0
  587. package/tests/setup.ts +16 -0
  588. package/tests/unit/.gitkeep +0 -0
  589. package/tests/unit/api/middlewares/authenticate.test.ts +446 -0
  590. package/tests/unit/providers/.gitkeep +0 -0
  591. package/tests/unit/providers/azure/azure-errors.test.ts +193 -0
  592. package/tests/unit/providers/azure/azure-retry.test.ts +254 -0
  593. package/tests/unit/providers/azure/graph-provider.test.ts +313 -0
  594. package/tests/unit/providers/ldap/ad-mappers.test.ts +392 -0
  595. package/tests/unit/providers/ldap/ldap-provider.test.ts +376 -0
  596. package/tests/unit/providers/ldap/ldap-retry.test.ts +377 -0
  597. package/tests/unit/providers/ldap/ldap-sanitizer.test.ts +301 -0
  598. package/tests/unit/sample.test.ts +19 -0
  599. package/tests/unit/services/.gitkeep +0 -0
  600. package/tests/unit/services/audit/detectors/ad/accounts.detector.test.ts +393 -0
  601. package/tests/unit/services/audit/detectors/ad/advanced.detector.test.ts +380 -0
  602. package/tests/unit/services/audit/detectors/ad/computers.detector.test.ts +440 -0
  603. package/tests/unit/services/audit/detectors/ad/groups.detector.test.ts +276 -0
  604. package/tests/unit/services/audit/detectors/ad/kerberos.detector.test.ts +215 -0
  605. package/tests/unit/services/audit/detectors/ad/password.detector.test.ts +226 -0
  606. package/tests/unit/services/audit/detectors/ad/permissions.detector.test.ts +244 -0
  607. package/tests/unit/services/audit/detectors/azure/app-security.detector.test.ts +349 -0
  608. package/tests/unit/services/audit/detectors/azure/conditional-access.detector.test.ts +374 -0
  609. package/tests/unit/services/audit/detectors/azure/privilege-security.detector.test.ts +374 -0
  610. package/tests/unit/services/audit/detectors/azure/user-security.detector.test.ts +297 -0
  611. package/tests/unit/services/auth/crypto.service.test.ts +296 -0
  612. package/tests/unit/services/auth/token.service.test.ts +579 -0
  613. package/tests/unit/services/export/export.service.test.ts +241 -0
  614. package/tests/unit/services/export/formatters/csv.formatter.test.ts +270 -0
  615. package/tests/unit/services/export/formatters/json.formatter.test.ts +258 -0
  616. package/tests/unit/utils/.gitkeep +0 -0
  617. package/tsconfig.json +50 -0
@@ -0,0 +1,685 @@
1
+ /**
2
+ * Groups Security Vulnerability Detector
3
+ *
4
+ * Detects group-related vulnerabilities in AD.
5
+ * Story 1.7: AD Vulnerability Detection Engine
6
+ *
7
+ * Vulnerabilities detected (14):
8
+ * - GPO_MODIFY_RIGHTS (High)
9
+ * - DNS_ADMINS_MEMBER (High)
10
+ * - OVERSIZED_GROUP_CRITICAL (High)
11
+ * - OVERSIZED_GROUP_HIGH (Medium)
12
+ * - OVERSIZED_GROUP (Medium)
13
+ * - PRE_WINDOWS_2000_ACCESS (Medium)
14
+ * - DANGEROUS_GROUP_NESTING (Medium)
15
+ * - GROUP_EMPTY_PRIVILEGED (Low) - Phase 2C
16
+ * - GROUP_CIRCULAR_NESTING (Medium) - Phase 2C
17
+ * - GROUP_EXCESSIVE_MEMBERS (Medium) - Phase 2C
18
+ * - BUILTIN_MODIFIED (High) - Phase 2C
19
+ * - GROUP_EVERYONE_IN_PRIVILEGED (Critical) - Phase 4
20
+ * - GROUP_AUTHENTICATED_USERS_PRIVILEGED (High) - Phase 4
21
+ * - GROUP_PROTECTED_USERS_EMPTY (Medium) - Phase 4
22
+ */
23
+
24
+ import { ADUser, ADGroup } from '../../../../types/ad.types';
25
+ import { Finding } from '../../../../types/finding.types';
26
+ import { toAffectedUserEntities, toAffectedADGroupEntities } from '../../../../utils/entity-converter';
27
+
28
+ /**
29
+ * Check for Group Policy Creator Owners membership
30
+ */
31
+ export function detectGpoModifyRights(users: ADUser[], includeDetails: boolean): Finding {
32
+ const affected = users.filter((u) => {
33
+ if (!u.memberOf) return false;
34
+ return u.memberOf.some((dn) => dn.includes('CN=Group Policy Creator Owners'));
35
+ });
36
+
37
+ return {
38
+ type: 'GPO_MODIFY_RIGHTS',
39
+ severity: 'high',
40
+ category: 'groups',
41
+ title: 'Group Policy Creator Owners Member',
42
+ description: 'Users in Group Policy Creator Owners group. Can create/modify GPOs and execute code on domain machines.',
43
+ count: affected.length,
44
+ affectedEntities: includeDetails ? toAffectedUserEntities(affected) : undefined,
45
+ };
46
+ }
47
+
48
+ /**
49
+ * Check for DnsAdmins membership
50
+ */
51
+ export function detectDnsAdminsMember(users: ADUser[], includeDetails: boolean): Finding {
52
+ const affected = users.filter((u) => {
53
+ if (!u.memberOf) return false;
54
+ return u.memberOf.some((dn) => dn.includes('CN=DnsAdmins'));
55
+ });
56
+
57
+ return {
58
+ type: 'DNS_ADMINS_MEMBER',
59
+ severity: 'high',
60
+ category: 'groups',
61
+ title: 'DnsAdmins Member',
62
+ description: 'Users in DnsAdmins group. Can load arbitrary DLLs on domain controllers (escalation to Domain Admin).',
63
+ count: affected.length,
64
+ affectedEntities: includeDetails ? toAffectedUserEntities(affected) : undefined,
65
+ };
66
+ }
67
+
68
+ /**
69
+ * Check for Pre-Windows 2000 Compatible Access membership
70
+ */
71
+ export function detectPreWindows2000Access(users: ADUser[], includeDetails: boolean): Finding {
72
+ const affected = users.filter((u) => {
73
+ if (!u.memberOf) return false;
74
+ return u.memberOf.some((dn) => dn.includes('CN=Pre-Windows 2000 Compatible Access'));
75
+ });
76
+
77
+ return {
78
+ type: 'PRE_WINDOWS_2000_ACCESS',
79
+ severity: 'medium',
80
+ category: 'groups',
81
+ title: 'Pre-Windows 2000 Compatible Access',
82
+ description: 'Pre-Windows 2000 Compatible Access group has members. Overly permissive read access to AD objects.',
83
+ count: affected.length,
84
+ affectedEntities: includeDetails ? toAffectedUserEntities(affected) : undefined,
85
+ };
86
+ }
87
+
88
+ /**
89
+ * Check for oversized groups (500+ members)
90
+ * PingCastle threshold: >500 members = critical
91
+ */
92
+ export function detectOversizedGroupCritical(groups: ADGroup[], includeDetails: boolean): Finding {
93
+ const affected = groups.filter((g) => {
94
+ if (!g.member) return false;
95
+ return g.member.length > 500;
96
+ });
97
+
98
+ return {
99
+ type: 'OVERSIZED_GROUP_CRITICAL',
100
+ severity: 'high',
101
+ category: 'groups',
102
+ title: 'Oversized Group (Critical)',
103
+ description: 'Groups with 500+ members. Management/audit difficulty, excessive privileges, performance issues.',
104
+ count: affected.length,
105
+ affectedEntities: includeDetails ? toAffectedADGroupEntities(affected) : undefined,
106
+ };
107
+ }
108
+
109
+ /**
110
+ * Check for oversized groups (200-500 members)
111
+ */
112
+ export function detectOversizedGroupHigh(groups: ADGroup[], includeDetails: boolean): Finding {
113
+ const affected = groups.filter((g) => {
114
+ if (!g.member) return false;
115
+ return g.member.length > 200 && g.member.length <= 500;
116
+ });
117
+
118
+ return {
119
+ type: 'OVERSIZED_GROUP_HIGH',
120
+ severity: 'medium',
121
+ category: 'groups',
122
+ title: 'Oversized Group (High)',
123
+ description: 'Groups with 200-500 members. Management difficulty and potential privilege creep.',
124
+ count: affected.length,
125
+ affectedEntities: includeDetails ? toAffectedADGroupEntities(affected) : undefined,
126
+ };
127
+ }
128
+
129
+ /**
130
+ * Check for oversized groups (100-500 members)
131
+ */
132
+ export function detectOversizedGroup(groups: ADGroup[], includeDetails: boolean): Finding {
133
+ const affected = groups.filter((g) => {
134
+ if (!g.member) return false;
135
+ return g.member.length > 100 && g.member.length <= 500;
136
+ });
137
+
138
+ return {
139
+ type: 'OVERSIZED_GROUP',
140
+ severity: 'medium',
141
+ category: 'groups',
142
+ title: 'Oversized Group',
143
+ description: 'Groups with 100-500 members. May indicate overly broad permissions.',
144
+ count: affected.length,
145
+ affectedEntities: includeDetails ? toAffectedADGroupEntities(affected) : undefined,
146
+ };
147
+ }
148
+
149
+ /**
150
+ * Check for dangerous group nesting (sensitive groups nested in less sensitive groups)
151
+ */
152
+ export function detectDangerousGroupNesting(groups: ADGroup[], includeDetails: boolean): Finding {
153
+ const protectedGroups = [
154
+ 'Domain Admins',
155
+ 'Enterprise Admins',
156
+ 'Schema Admins',
157
+ 'Administrators',
158
+ 'Account Operators',
159
+ 'Backup Operators',
160
+ 'Server Operators',
161
+ 'Print Operators',
162
+ ];
163
+
164
+ const affected = groups.filter((g) => {
165
+ if (!g.memberOf) return false;
166
+
167
+ // Check if this is a protected group
168
+ const isProtected = protectedGroups.some((pg) => g.dn.includes(`CN=${pg}`));
169
+ if (!isProtected) return false;
170
+
171
+ // Check if it's nested in a non-protected group
172
+ const hasUnexpectedNesting = g.memberOf.some((dn) => {
173
+ return !protectedGroups.some((pg) => dn.includes(`CN=${pg}`));
174
+ });
175
+
176
+ return hasUnexpectedNesting;
177
+ });
178
+
179
+ return {
180
+ type: 'DANGEROUS_GROUP_NESTING',
181
+ severity: 'medium',
182
+ category: 'groups',
183
+ title: 'Dangerous Group Nesting',
184
+ description: 'Sensitive group nested in less sensitive group. Unintended privilege escalation path.',
185
+ count: affected.length,
186
+ affectedEntities: includeDetails ? toAffectedADGroupEntities(affected) : undefined,
187
+ };
188
+ }
189
+
190
+ // ==================== PHASE 2C DETECTORS ====================
191
+
192
+ /**
193
+ * Detect empty privileged groups
194
+ * Privileged groups should either be used or documented as intentionally empty
195
+ */
196
+ export function detectGroupEmptyPrivileged(groups: ADGroup[], includeDetails: boolean): Finding {
197
+ const privilegedGroups = [
198
+ 'Domain Admins',
199
+ 'Enterprise Admins',
200
+ 'Schema Admins',
201
+ 'Administrators',
202
+ 'Account Operators',
203
+ 'Server Operators',
204
+ 'Backup Operators',
205
+ 'Print Operators',
206
+ 'DnsAdmins',
207
+ 'Group Policy Creator Owners',
208
+ ];
209
+
210
+ const affected = groups.filter((g) => {
211
+ const name = g.sAMAccountName || g.displayName || '';
212
+ const isPrivileged = privilegedGroups.some(
213
+ (pg) => name.toLowerCase() === pg.toLowerCase() || g.dn.toLowerCase().includes(`cn=${pg.toLowerCase()}`)
214
+ );
215
+
216
+ if (!isPrivileged) return false;
217
+
218
+ // Check if group is empty
219
+ const memberCount = g.member?.length ?? 0;
220
+ return memberCount === 0;
221
+ });
222
+
223
+ return {
224
+ type: 'GROUP_EMPTY_PRIVILEGED',
225
+ severity: 'low',
226
+ category: 'groups',
227
+ title: 'Empty Privileged Group',
228
+ description:
229
+ 'Privileged groups with no members. While not a vulnerability, empty admin groups may indicate misconfiguration or unused infrastructure.',
230
+ count: affected.length,
231
+ affectedEntities: includeDetails ? toAffectedADGroupEntities(affected) : undefined,
232
+ details:
233
+ affected.length > 0
234
+ ? {
235
+ groups: affected.map((g) => g.sAMAccountName || g.dn),
236
+ recommendation: 'Document intentionally empty groups or remove if unused.',
237
+ }
238
+ : undefined,
239
+ };
240
+ }
241
+
242
+ /**
243
+ * Detect circular group nesting
244
+ * Groups that are members of each other create infinite loops
245
+ */
246
+ export function detectGroupCircularNesting(groups: ADGroup[], includeDetails: boolean): Finding {
247
+ const groupDnMap = new Map<string, ADGroup>();
248
+ for (const g of groups) {
249
+ groupDnMap.set(g.dn.toLowerCase(), g);
250
+ }
251
+
252
+ const circularGroups: ADGroup[] = [];
253
+ const visited = new Set<string>();
254
+
255
+ const detectCycle = (groupDn: string, path: Set<string>): boolean => {
256
+ const normalizedDn = groupDn.toLowerCase();
257
+ if (path.has(normalizedDn)) return true; // Cycle detected
258
+ if (visited.has(normalizedDn)) return false; // Already checked, no cycle
259
+
260
+ visited.add(normalizedDn);
261
+ path.add(normalizedDn);
262
+
263
+ const group = groupDnMap.get(normalizedDn);
264
+ if (group?.memberOf) {
265
+ for (const parentDn of group.memberOf) {
266
+ if (groupDnMap.has(parentDn.toLowerCase())) {
267
+ if (detectCycle(parentDn, path)) {
268
+ return true;
269
+ }
270
+ }
271
+ }
272
+ }
273
+
274
+ path.delete(normalizedDn);
275
+ return false;
276
+ };
277
+
278
+ for (const group of groups) {
279
+ visited.clear();
280
+ if (detectCycle(group.dn, new Set())) {
281
+ circularGroups.push(group);
282
+ }
283
+ }
284
+
285
+ return {
286
+ type: 'GROUP_CIRCULAR_NESTING',
287
+ severity: 'medium',
288
+ category: 'groups',
289
+ title: 'Circular Group Nesting',
290
+ description:
291
+ 'Groups contain circular membership references. This can cause authentication issues and makes privilege analysis unreliable.',
292
+ count: circularGroups.length,
293
+ affectedEntities: includeDetails ? toAffectedADGroupEntities(circularGroups) : undefined,
294
+ details:
295
+ circularGroups.length > 0
296
+ ? {
297
+ recommendation: 'Remove circular nesting by reviewing and restructuring group membership.',
298
+ impact: 'May cause token bloat, authentication failures, and unreliable access control.',
299
+ }
300
+ : undefined,
301
+ };
302
+ }
303
+
304
+ /**
305
+ * Detect groups with excessive direct members
306
+ * Large groups are difficult to manage and review
307
+ */
308
+ export function detectGroupExcessiveMembers(groups: ADGroup[], includeDetails: boolean): Finding {
309
+ const EXCESSIVE_THRESHOLD = 100;
310
+
311
+ const affected = groups.filter((g) => {
312
+ const memberCount = g.member?.length ?? 0;
313
+ return memberCount > EXCESSIVE_THRESHOLD;
314
+ });
315
+
316
+ // Sort by member count (most members first)
317
+ affected.sort((a, b) => (b.member?.length ?? 0) - (a.member?.length ?? 0));
318
+
319
+ return {
320
+ type: 'GROUP_EXCESSIVE_MEMBERS',
321
+ severity: 'medium',
322
+ category: 'groups',
323
+ title: 'Group with Excessive Members',
324
+ description: `Groups with more than ${EXCESSIVE_THRESHOLD} direct members. Large groups are difficult to audit and may grant unintended access.`,
325
+ count: affected.length,
326
+ affectedEntities: includeDetails ? toAffectedADGroupEntities(affected) : undefined,
327
+ details:
328
+ affected.length > 0
329
+ ? {
330
+ threshold: EXCESSIVE_THRESHOLD,
331
+ largestGroups: affected.slice(0, 5).map((g) => ({
332
+ name: g.sAMAccountName || g.dn,
333
+ memberCount: g.member?.length ?? 0,
334
+ })),
335
+ recommendation:
336
+ 'Review large groups and consider breaking into smaller, role-based groups for better access control.',
337
+ }
338
+ : undefined,
339
+ };
340
+ }
341
+
342
+ /**
343
+ * Detect builtin groups with non-standard members
344
+ * Builtin groups should only contain expected system accounts
345
+ */
346
+ export function detectBuiltinModified(groups: ADGroup[], includeDetails: boolean): Finding {
347
+ // Builtin groups and their expected default members
348
+ const builtinDefaults: { [key: string]: string[] } = {
349
+ Administrators: ['Administrator', 'Domain Admins', 'Enterprise Admins'],
350
+ Users: ['Domain Users', 'Authenticated Users', 'INTERACTIVE'],
351
+ Guests: ['Guest', 'Domain Guests'],
352
+ 'Remote Desktop Users': [],
353
+ 'Network Configuration Operators': [],
354
+ 'Performance Monitor Users': [],
355
+ 'Performance Log Users': [],
356
+ 'Distributed COM Users': [],
357
+ 'IIS_IUSRS': [],
358
+ 'Cryptographic Operators': [],
359
+ 'Event Log Readers': [],
360
+ 'Certificate Service DCOM Access': [],
361
+ };
362
+
363
+ const affected = groups.filter((g) => {
364
+ const name = g.sAMAccountName || '';
365
+
366
+ // Check if it's a builtin group we monitor
367
+ if (!builtinDefaults[name]) return false;
368
+
369
+ const expectedMembers = builtinDefaults[name];
370
+ const actualMembers = g.member ?? [];
371
+
372
+ // Check for unexpected members
373
+ const hasUnexpectedMembers = actualMembers.some((memberDn) => {
374
+ const memberCn = memberDn.match(/CN=([^,]+)/i)?.[1] || '';
375
+ // Check if this member is in the expected list
376
+ return !expectedMembers.some((exp) => memberCn.toLowerCase().includes(exp.toLowerCase()));
377
+ });
378
+
379
+ return hasUnexpectedMembers;
380
+ });
381
+
382
+ return {
383
+ type: 'BUILTIN_MODIFIED',
384
+ severity: 'high',
385
+ category: 'groups',
386
+ title: 'Builtin Group Modified',
387
+ description:
388
+ 'Builtin groups contain non-standard members. This may indicate privilege escalation or backdoor access.',
389
+ count: affected.length,
390
+ affectedEntities: includeDetails ? toAffectedADGroupEntities(affected) : undefined,
391
+ details:
392
+ affected.length > 0
393
+ ? {
394
+ groups: affected.map((g) => g.sAMAccountName || g.dn),
395
+ recommendation:
396
+ 'Review membership of builtin groups and remove unexpected members. Document any intentional additions.',
397
+ risk: 'Attackers often add accounts to builtin groups for persistent access.',
398
+ }
399
+ : undefined,
400
+ };
401
+ }
402
+
403
+ /**
404
+ * Detect Everyone group in privileged groups
405
+ *
406
+ * The Everyone principal should never be a member of privileged groups.
407
+ * This grants all users (including anonymous) privileged access.
408
+ *
409
+ * @param groups - Array of AD groups
410
+ * @param includeDetails - Whether to include affected entity details
411
+ * @returns Finding for GROUP_EVERYONE_IN_PRIVILEGED
412
+ */
413
+ export function detectGroupEveryoneInPrivileged(
414
+ groups: ADGroup[],
415
+ includeDetails: boolean
416
+ ): Finding {
417
+ const privilegedGroups = [
418
+ 'Domain Admins',
419
+ 'Enterprise Admins',
420
+ 'Schema Admins',
421
+ 'Administrators',
422
+ 'Account Operators',
423
+ 'Server Operators',
424
+ 'Backup Operators',
425
+ 'Print Operators',
426
+ ];
427
+
428
+ const affected = groups.filter((g) => {
429
+ const groupName = g.sAMAccountName || g.cn || '';
430
+ const isPrivileged = privilegedGroups.some(
431
+ (pg) => groupName.toLowerCase() === pg.toLowerCase()
432
+ );
433
+ if (!isPrivileged || !g.member) return false;
434
+
435
+ // Check if Everyone (S-1-1-0) or World is a member
436
+ return g.member.some(
437
+ (m) =>
438
+ m.toLowerCase().includes('everyone') ||
439
+ m.includes('S-1-1-0') ||
440
+ m.toLowerCase().includes('world')
441
+ );
442
+ });
443
+
444
+ return {
445
+ type: 'GROUP_EVERYONE_IN_PRIVILEGED',
446
+ severity: 'critical',
447
+ category: 'groups',
448
+ title: 'Everyone in Privileged Group',
449
+ description:
450
+ 'The Everyone principal is a member of a privileged group. ' +
451
+ 'This grants ALL users (including anonymous) administrative privileges.',
452
+ count: affected.length,
453
+ affectedEntities: includeDetails ? toAffectedADGroupEntities(affected) : undefined,
454
+ details: {
455
+ recommendation: 'Immediately remove Everyone from privileged groups.',
456
+ risk: 'Complete domain compromise - anyone can authenticate as admin.',
457
+ },
458
+ };
459
+ }
460
+
461
+ /**
462
+ * Detect Authenticated Users in privileged groups
463
+ *
464
+ * Authenticated Users should not be members of privileged groups.
465
+ * This grants all domain users admin access.
466
+ *
467
+ * @param groups - Array of AD groups
468
+ * @param includeDetails - Whether to include affected entity details
469
+ * @returns Finding for GROUP_AUTHENTICATED_USERS_PRIVILEGED
470
+ */
471
+ export function detectGroupAuthenticatedUsersPrivileged(
472
+ groups: ADGroup[],
473
+ includeDetails: boolean
474
+ ): Finding {
475
+ const privilegedGroups = [
476
+ 'Domain Admins',
477
+ 'Enterprise Admins',
478
+ 'Schema Admins',
479
+ 'Administrators',
480
+ 'Account Operators',
481
+ 'Server Operators',
482
+ 'Backup Operators',
483
+ ];
484
+
485
+ const affected = groups.filter((g) => {
486
+ const groupName = g.sAMAccountName || g.cn || '';
487
+ const isPrivileged = privilegedGroups.some(
488
+ (pg) => groupName.toLowerCase() === pg.toLowerCase()
489
+ );
490
+ if (!isPrivileged || !g.member) return false;
491
+
492
+ // Check if Authenticated Users (S-1-5-11) is a member
493
+ return g.member.some(
494
+ (m) =>
495
+ m.toLowerCase().includes('authenticated users') ||
496
+ m.includes('S-1-5-11') ||
497
+ m.toLowerCase().includes('utilisateurs authentifiés')
498
+ );
499
+ });
500
+
501
+ return {
502
+ type: 'GROUP_AUTHENTICATED_USERS_PRIVILEGED',
503
+ severity: 'high',
504
+ category: 'groups',
505
+ title: 'Authenticated Users in Privileged Group',
506
+ description:
507
+ 'Authenticated Users principal is a member of a privileged group. ' +
508
+ 'This grants ALL authenticated domain users administrative privileges.',
509
+ count: affected.length,
510
+ affectedEntities: includeDetails ? toAffectedADGroupEntities(affected) : undefined,
511
+ details: {
512
+ recommendation: 'Remove Authenticated Users from privileged groups immediately.',
513
+ risk: 'Any domain user can perform administrative actions.',
514
+ },
515
+ };
516
+ }
517
+
518
+ /**
519
+ * Detect empty Protected Users group
520
+ *
521
+ * The Protected Users group provides enhanced security for privileged accounts.
522
+ * If empty, privileged accounts lack these protections.
523
+ *
524
+ * @param groups - Array of AD groups
525
+ * @param _includeDetails - Whether to include affected entity details
526
+ * @returns Finding for GROUP_PROTECTED_USERS_EMPTY
527
+ */
528
+ export function detectGroupProtectedUsersEmpty(
529
+ groups: ADGroup[],
530
+ _includeDetails: boolean
531
+ ): Finding {
532
+ const protectedUsersGroup = groups.find(
533
+ (g) =>
534
+ (g.sAMAccountName || g.cn || '').toLowerCase() === 'protected users'
535
+ );
536
+
537
+ const isEmpty =
538
+ !protectedUsersGroup ||
539
+ !protectedUsersGroup.member ||
540
+ protectedUsersGroup.member.length === 0;
541
+
542
+ return {
543
+ type: 'GROUP_PROTECTED_USERS_EMPTY',
544
+ severity: 'medium',
545
+ category: 'groups',
546
+ title: 'Protected Users Group Empty',
547
+ description:
548
+ 'The Protected Users group has no members. ' +
549
+ 'Privileged accounts should be added to this group for enhanced security (NTLM disabled, Kerberos delegation blocked, credential caching prevented).',
550
+ count: isEmpty ? 1 : 0,
551
+ details: {
552
+ memberCount: protectedUsersGroup?.member?.length || 0,
553
+ recommendation:
554
+ 'Add Domain Admins, Enterprise Admins, and other privileged accounts to Protected Users group.',
555
+ benefits: [
556
+ 'NTLM authentication disabled',
557
+ 'Kerberos delegation blocked',
558
+ 'Credential caching prevented',
559
+ 'DES/RC4 encryption disabled',
560
+ ],
561
+ },
562
+ };
563
+ }
564
+
565
+ /**
566
+ * Detect excessive privileged accounts
567
+ * Flags when there are too many accounts in high-privilege groups
568
+ * PingCastle threshold: > 10 Domain Admins, > 50 total privileged
569
+ */
570
+ export function detectExcessivePrivilegedAccounts(
571
+ users: ADUser[],
572
+ groups: ADGroup[],
573
+ includeDetails: boolean
574
+ ): Finding {
575
+ const privilegedGroupNames = [
576
+ 'Domain Admins',
577
+ 'Enterprise Admins',
578
+ 'Schema Admins',
579
+ 'Administrators',
580
+ 'Account Operators',
581
+ 'Backup Operators',
582
+ 'Server Operators',
583
+ 'Print Operators',
584
+ ];
585
+
586
+ // Count unique privileged users
587
+ const privilegedUsers = new Set<string>();
588
+ const groupCounts: Record<string, number> = {};
589
+
590
+ for (const user of users) {
591
+ if (!user.memberOf) continue;
592
+ for (const groupDn of user.memberOf) {
593
+ for (const groupName of privilegedGroupNames) {
594
+ if (groupDn.toUpperCase().includes(`CN=${groupName.toUpperCase()}`)) {
595
+ privilegedUsers.add(user.dn);
596
+ groupCounts[groupName] = (groupCounts[groupName] || 0) + 1;
597
+ }
598
+ }
599
+ }
600
+ }
601
+
602
+ // Also count from group membership directly
603
+ for (const group of groups) {
604
+ const groupName = privilegedGroupNames.find((name) =>
605
+ group.sAMAccountName?.toUpperCase() === name.toUpperCase() ||
606
+ group.dn?.toUpperCase().includes(`CN=${name.toUpperCase()}`)
607
+ );
608
+ if (groupName && group.member) {
609
+ groupCounts[groupName] = Math.max(groupCounts[groupName] || 0, group.member.length);
610
+ }
611
+ }
612
+
613
+ const totalPrivileged = privilegedUsers.size;
614
+ const domainAdmins = groupCounts['Domain Admins'] || 0;
615
+ const enterpriseAdmins = groupCounts['Enterprise Admins'] || 0;
616
+
617
+ // Flag if > 10 Domain Admins OR > 50 total privileged (PingCastle thresholds)
618
+ const isExcessive = domainAdmins > 10 || totalPrivileged > 50;
619
+
620
+ return {
621
+ type: 'EXCESSIVE_PRIVILEGED_ACCOUNTS',
622
+ severity: isExcessive ? 'medium' : 'low',
623
+ category: 'groups',
624
+ title: 'Excessive Privileged Accounts',
625
+ description:
626
+ 'Large number of accounts with administrative privileges increases attack surface. ' +
627
+ 'Each privileged account is a potential target for credential theft.',
628
+ count: isExcessive ? totalPrivileged : 0,
629
+ affectedEntities: includeDetails && isExcessive
630
+ ? Array.from(privilegedUsers).map((dn) => {
631
+ const user = users.find((u) => u.dn === dn);
632
+ if (user) {
633
+ const entities = toAffectedUserEntities([user]);
634
+ return entities[0] || dn;
635
+ }
636
+ return dn;
637
+ })
638
+ : undefined,
639
+ details: {
640
+ totalPrivilegedUsers: totalPrivileged,
641
+ domainAdmins,
642
+ enterpriseAdmins,
643
+ schemaAdmins: groupCounts['Schema Admins'] || 0,
644
+ administrators: groupCounts['Administrators'] || 0,
645
+ accountOperators: groupCounts['Account Operators'] || 0,
646
+ backupOperators: groupCounts['Backup Operators'] || 0,
647
+ serverOperators: groupCounts['Server Operators'] || 0,
648
+ printOperators: groupCounts['Print Operators'] || 0,
649
+ threshold: 'Domain Admins > 10 or total privileged > 50',
650
+ recommendation: 'Review privileged group memberships and apply least privilege principle.',
651
+ },
652
+ };
653
+ }
654
+
655
+ /**
656
+ * Detect all group-related vulnerabilities
657
+ */
658
+ export function detectGroupsVulnerabilities(
659
+ users: ADUser[],
660
+ groups: ADGroup[],
661
+ includeDetails: boolean
662
+ ): Finding[] {
663
+ return [
664
+ // User membership checks
665
+ detectGpoModifyRights(users, includeDetails),
666
+ detectDnsAdminsMember(users, includeDetails),
667
+ detectPreWindows2000Access(users, includeDetails),
668
+ // Group analysis checks
669
+ detectOversizedGroupCritical(groups, includeDetails),
670
+ detectOversizedGroupHigh(groups, includeDetails),
671
+ detectOversizedGroup(groups, includeDetails),
672
+ detectDangerousGroupNesting(groups, includeDetails),
673
+ // Phase 2C: Enhanced detections
674
+ detectGroupEmptyPrivileged(groups, includeDetails),
675
+ detectGroupCircularNesting(groups, includeDetails),
676
+ detectGroupExcessiveMembers(groups, includeDetails),
677
+ detectBuiltinModified(groups, includeDetails),
678
+ // Phase 4: Advanced detections
679
+ detectGroupEveryoneInPrivileged(groups, includeDetails),
680
+ detectGroupAuthenticatedUsersPrivileged(groups, includeDetails),
681
+ detectGroupProtectedUsersEmpty(groups, includeDetails),
682
+ // NEW: Excessive privileged accounts
683
+ detectExcessivePrivilegedAccounts(users, groups, includeDetails),
684
+ ].filter((finding) => finding.count > 0);
685
+ }