0sec-cli 0.15.0 → 0.17.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 (209) hide show
  1. package/0sec.js +322 -0
  2. package/README.md +63 -52
  3. package/attacks/data-exfiltration/pii-leakage.yaml +27 -0
  4. package/attacks/encoding-bypass/base64-encoding.yaml +24 -0
  5. package/attacks/jailbreak/dan-roleplay.yaml +27 -0
  6. package/attacks/jailbreak/hypothetical-scenario.yaml +25 -0
  7. package/attacks/jailbreak/multilingual-bypass.yaml +22 -0
  8. package/attacks/output-manipulation/harmful-content.yaml +25 -0
  9. package/attacks/prompt-injection/context-manipulation.yaml +32 -0
  10. package/attacks/prompt-injection/direct-injection.yaml +28 -0
  11. package/attacks/prompt-injection/indirect-injection.yaml +33 -0
  12. package/attacks/system-prompt-extraction/direct-ask.yaml +30 -0
  13. package/attacks/system-prompt-extraction/markdown-exfil.yaml +26 -0
  14. package/attacks/tool-misuse/ssrf-via-tools.yaml +27 -0
  15. package/chunks/adapt-loop-ECQG7454.js +18 -0
  16. package/chunks/adgraph-JLGA6RYI.js +54 -0
  17. package/chunks/agent/skills/frameworks/entra-id.yaml +63 -0
  18. package/chunks/agent/skills/frameworks/graphql-introspection.yaml +116 -0
  19. package/chunks/agent/skills/frameworks/nextjs.yaml +82 -0
  20. package/chunks/agent/skills/frameworks/python-web.yaml +85 -0
  21. package/chunks/agent/skills/frameworks/supabase.yaml +83 -0
  22. package/chunks/agent/skills/frameworks/wordpress-deep.yaml +122 -0
  23. package/chunks/agent/skills/techniques/ad-attack-paths.yaml +57 -0
  24. package/chunks/agent/skills/techniques/advisory-disclosure.yaml +59 -0
  25. package/chunks/agent/skills/techniques/assumption-mining.yaml +53 -0
  26. package/chunks/agent/skills/techniques/blind-exploitation.yaml +143 -0
  27. package/chunks/agent/skills/techniques/crypto-misuse.yaml +88 -0
  28. package/chunks/agent/skills/techniques/cve-poc-adaptation.yaml +82 -0
  29. package/chunks/agent/skills/techniques/entra-attack-paths.yaml +55 -0
  30. package/chunks/agent/skills/techniques/http-conformance-diff.yaml +48 -0
  31. package/chunks/agent/skills/techniques/jwt-attacks.yaml +137 -0
  32. package/chunks/agent/skills/techniques/kernel-weaponization.yaml +53 -0
  33. package/chunks/agent/skills/techniques/llm-excessive-agency.yaml +55 -0
  34. package/chunks/agent/skills/techniques/llm-insecure-output-handling.yaml +56 -0
  35. package/chunks/agent/skills/techniques/llm-prompt-injection.yaml +54 -0
  36. package/chunks/agent/skills/techniques/llm-prompt-layer-write.yaml +68 -0
  37. package/chunks/agent/skills/techniques/llm-rag-poisoning.yaml +57 -0
  38. package/chunks/agent/skills/techniques/llm-safety-eval.yaml +51 -0
  39. package/chunks/agent/skills/techniques/npm-ecosystem.yaml +51 -0
  40. package/chunks/agent/skills/techniques/poc-verification.yaml +55 -0
  41. package/chunks/agent/skills/techniques/race-condition.yaml +122 -0
  42. package/chunks/agent/skills/techniques/scoped-fix.yaml +49 -0
  43. package/chunks/agent/skills/techniques/seedless-depth-review.yaml +59 -0
  44. package/chunks/agent/skills/techniques/spec-differential.yaml +48 -0
  45. package/chunks/agent/skills/techniques/variant-hunting.yaml +55 -0
  46. package/chunks/agent/skills/vulnerabilities/cardano-eutxo-validators.yaml +72 -0
  47. package/chunks/agent/skills/vulnerabilities/command-injection.yaml +99 -0
  48. package/chunks/agent/skills/vulnerabilities/deserialization-chains.yaml +106 -0
  49. package/chunks/agent/skills/vulnerabilities/native-memory-safety.yaml +93 -0
  50. package/chunks/agent/skills/vulnerabilities/path-traversal.yaml +78 -0
  51. package/chunks/agent/skills/vulnerabilities/prototype-pollution.yaml +132 -0
  52. package/chunks/agent/skills/vulnerabilities/request-smuggling.yaml +129 -0
  53. package/chunks/agent/skills/vulnerabilities/sqli-advanced.yaml +102 -0
  54. package/chunks/agent/skills/vulnerabilities/ssrf-bypass.yaml +84 -0
  55. package/chunks/agent/skills/vulnerabilities/ssti-exploitation.yaml +112 -0
  56. package/chunks/agent/skills/vulnerabilities/structural-sqli.yaml +91 -0
  57. package/chunks/appsec-catalog-CBWHGTEL.js +24 -0
  58. package/chunks/artifact-scraper-GJEZMOHF.js +34 -0
  59. package/chunks/assumption-mining-BVMMUZHB.js +79 -0
  60. package/chunks/chunk-2CJ776PV.js +2430 -0
  61. package/chunks/chunk-2RMLOJVB.js +47 -0
  62. package/chunks/chunk-2SANI5RH.js +4728 -0
  63. package/chunks/chunk-3MOLBTLS.js +953 -0
  64. package/chunks/chunk-3QFDYBZQ.js +5108 -0
  65. package/chunks/chunk-47TQJWDH.js +3729 -0
  66. package/chunks/chunk-4Y4KQJXE.js +600 -0
  67. package/chunks/chunk-53G27VPS.js +136 -0
  68. package/chunks/chunk-57ZENEX2.js +169 -0
  69. package/chunks/chunk-5G3ZXFBW.js +182 -0
  70. package/chunks/chunk-6LKRLK2R.js +542 -0
  71. package/chunks/chunk-7DQEV5QI.js +287 -0
  72. package/chunks/chunk-A6CLR72I.js +235 -0
  73. package/chunks/chunk-BKZFDZ23.js +361 -0
  74. package/chunks/chunk-CLHCDHP4.js +471 -0
  75. package/chunks/chunk-D6S3IIPG.js +518 -0
  76. package/chunks/chunk-DN25OQQA.js +1070 -0
  77. package/chunks/chunk-DW5UWPFY.js +275 -0
  78. package/chunks/chunk-F3WBKITT.js +687 -0
  79. package/chunks/chunk-H2FFLZNK.js +3 -0
  80. package/chunks/chunk-H44E2CRN.js +193 -0
  81. package/chunks/chunk-HDWV7PGI.js +596 -0
  82. package/chunks/chunk-HE7LCA7G.js +381 -0
  83. package/chunks/chunk-HT6P7RY3.js +2597 -0
  84. package/chunks/chunk-IOL7D5YV.js +515 -0
  85. package/chunks/chunk-IORC6MQX.js +72828 -0
  86. package/chunks/chunk-IR537GON.js +49 -0
  87. package/chunks/chunk-K26SZ37E.js +5735 -0
  88. package/chunks/chunk-KKGE5RQE.js +1094 -0
  89. package/chunks/chunk-KLTNTE2Z.js +121 -0
  90. package/chunks/chunk-KTQDLNSR.js +1732 -0
  91. package/chunks/chunk-LOHTE223.js +2572 -0
  92. package/chunks/chunk-LP3HHYQU.js +245 -0
  93. package/chunks/chunk-MMLDQR4H.js +852 -0
  94. package/chunks/chunk-MYVT64FN.js +16 -0
  95. package/chunks/chunk-O462Y7P2.js +33019 -0
  96. package/chunks/chunk-OEFNRYI2.js +150 -0
  97. package/chunks/chunk-P6WKNFWX.js +1968 -0
  98. package/chunks/chunk-QI233I24.js +333 -0
  99. package/chunks/chunk-QJQKHO7G.js +917 -0
  100. package/chunks/chunk-QKICO43A.js +808 -0
  101. package/chunks/chunk-QOKTUOU2.js +102 -0
  102. package/chunks/chunk-RDZYQQLW.js +596 -0
  103. package/chunks/chunk-RJWOYEOG.js +271 -0
  104. package/chunks/chunk-RRMJC3ZE.js +105 -0
  105. package/chunks/chunk-RWONANDA.js +973 -0
  106. package/chunks/chunk-SAFFWQW4.js +5921 -0
  107. package/chunks/chunk-SF4KZ4O3.js +502 -0
  108. package/chunks/chunk-SNKTC4BP.js +1422 -0
  109. package/chunks/chunk-SOG2U7B3.js +662 -0
  110. package/chunks/chunk-SZJCPG2I.js +110 -0
  111. package/chunks/chunk-UJ4IK5PO.js +2010 -0
  112. package/chunks/chunk-UM3ZNQIM.js +9329 -0
  113. package/chunks/chunk-VGRDNSHA.js +3249 -0
  114. package/chunks/chunk-VQG4FT5D.js +685 -0
  115. package/chunks/chunk-WKNNZVJS.js +2798 -0
  116. package/chunks/chunk-WU6AFRAZ.js +1167 -0
  117. package/chunks/chunk-WVTBZEQO.js +1531 -0
  118. package/chunks/chunk-YLMN3N25.js +4054 -0
  119. package/chunks/commands-U3AMV5ZU.js +16795 -0
  120. package/chunks/corpus-v1.json +403 -0
  121. package/chunks/cost-ledger-ZCKMBJEN.js +13 -0
  122. package/chunks/data/appsec-archetypes.json +102 -0
  123. package/chunks/data/chromium-archetypes.json +204 -0
  124. package/chunks/data/freebsd-archetypes.json +171 -0
  125. package/chunks/data/kernel-archetypes.json +611 -0
  126. package/chunks/db-26NGQFKO.js +16 -0
  127. package/chunks/disclose-A6AEIEDA.js +132 -0
  128. package/chunks/dist-FDKALV4R.js +2772 -0
  129. package/chunks/dist-GL66KMUX.js +74 -0
  130. package/chunks/dist-JR67XKYO.js +159 -0
  131. package/chunks/eval-runner-DDLE5RQ3.js +27 -0
  132. package/chunks/example-manifest.json +95 -0
  133. package/chunks/exploit-agent-XP23ISN7.js +98 -0
  134. package/chunks/exploit-autoclimb-E6T7RRSC.js +81 -0
  135. package/chunks/exploit-climb-2FAUP6XU.js +358 -0
  136. package/chunks/fix-IG7LYXH3.js +12 -0
  137. package/chunks/github-issues-MJ6OYOOU.js +157 -0
  138. package/chunks/harness-HWOYFKFY.js +22 -0
  139. package/chunks/http-conformance-DU66MZIU.js +11 -0
  140. package/chunks/http-sender-GWH2IYEA.js +10 -0
  141. package/chunks/hunt-scan-XPELSPQQ.js +38 -0
  142. package/chunks/identity-6ZAIIWOR.js +191 -0
  143. package/chunks/kernel-primitive-TENE3R7T.js +44 -0
  144. package/chunks/kernel-vm-runner-4F6QSNFY.js +62 -0
  145. package/chunks/memsafety-scan-J7SECV5W.js +16 -0
  146. package/chunks/native-loop-NTONUDP7.js +54 -0
  147. package/chunks/npm-detectors-KB5Y5ZFX.js +69 -0
  148. package/chunks/npm-dynamic-discovery-AHROOZDB.js +13 -0
  149. package/chunks/orchestrate-ZUWAUWBC.js +62 -0
  150. package/chunks/pipeline-FCARFZU3.js +14 -0
  151. package/chunks/pre-recon-cve-66EB6G4M.js +351 -0
  152. package/chunks/prepare-MYY743TK.js +13 -0
  153. package/chunks/process-3Q7QJIOZ.js +13 -0
  154. package/chunks/replay-runner-RRR4E2A7.js +39 -0
  155. package/chunks/run-ESNN4V5W.js +32632 -0
  156. package/chunks/runtime-62ZQAH7H.js +43 -0
  157. package/chunks/runtime-J7PLXZNM.js +12 -0
  158. package/chunks/scan-stream-FHI2FYZE.js +96 -0
  159. package/chunks/scope-BI7BF4ZY.js +18 -0
  160. package/chunks/session-store-BCFQYDCE.js +28 -0
  161. package/chunks/source-files-PWRQR6LY.js +12 -0
  162. package/chunks/specdrift-WCLH6TTQ.js +19 -0
  163. package/chunks/variant-candidates-6KM6F6MD.js +13 -0
  164. package/chunks/web-recon-prepass-DPVCBRZA.js +1148 -0
  165. package/dashboard/assets/0sec-icon-66SreztZ.gif +0 -0
  166. package/dashboard/assets/bot-yILPnRgD.js +1 -0
  167. package/dashboard/assets/chevron-down-BeDJ-Vka.js +1 -0
  168. package/dashboard/assets/circle-alert-BEnMBMT-.js +1 -0
  169. package/dashboard/assets/client-DRYsuOGl.js +9 -0
  170. package/dashboard/assets/copy-Bi5vzoF9.js +1 -0
  171. package/dashboard/assets/desktop-CXTQonNm.js +32 -0
  172. package/dashboard/assets/desktop-NOekk4QS.css +1 -0
  173. package/dashboard/assets/dist-CmX-h7a4.js +1 -0
  174. package/dashboard/assets/dist-DAwYQmf_.js +45 -0
  175. package/dashboard/assets/findings-page-CACW9nw2.js +5 -0
  176. package/dashboard/assets/format-PoISqsES.js +1 -0
  177. package/dashboard/assets/geist-cyrillic-ext-wght-normal-DjL33-gN.woff2 +0 -0
  178. package/dashboard/assets/geist-cyrillic-wght-normal-BEAKL7Jp.woff2 +0 -0
  179. package/dashboard/assets/geist-latin-ext-wght-normal-DC-KSUi6.woff2 +0 -0
  180. package/dashboard/assets/geist-latin-wght-normal-BgDaEnEv.woff2 +0 -0
  181. package/dashboard/assets/geist-vietnamese-wght-normal-6IgcOCM7.woff2 +0 -0
  182. package/dashboard/assets/ibm-plex-mono-cyrillic-400-normal-BSMlKf0J.woff2 +0 -0
  183. package/dashboard/assets/ibm-plex-mono-cyrillic-400-normal-CEL4l2ZJ.woff +0 -0
  184. package/dashboard/assets/ibm-plex-mono-cyrillic-ext-400-normal-DMdlQ8Kv.woff +0 -0
  185. package/dashboard/assets/ibm-plex-mono-cyrillic-ext-400-normal-xuaO2J-f.woff2 +0 -0
  186. package/dashboard/assets/ibm-plex-mono-latin-400-normal-CvHOgSBP.woff +0 -0
  187. package/dashboard/assets/ibm-plex-mono-latin-400-normal-DMJ8VG8y.woff2 +0 -0
  188. package/dashboard/assets/ibm-plex-mono-latin-ext-400-normal-BmRBH3aV.woff2 +0 -0
  189. package/dashboard/assets/ibm-plex-mono-latin-ext-400-normal-D3D2R8hC.woff +0 -0
  190. package/dashboard/assets/ibm-plex-mono-vietnamese-400-normal-BulugwFq.woff2 +0 -0
  191. package/dashboard/assets/ibm-plex-mono-vietnamese-400-normal-DDuiU_S-.woff +0 -0
  192. package/dashboard/assets/jsx-runtime-C7oxC63R.js +1 -0
  193. package/dashboard/assets/live-page-DrgQqQK5.js +1 -0
  194. package/dashboard/assets/meta-tile-CcskIV_o.js +1 -0
  195. package/dashboard/assets/operations-BKE8T-vY.css +2 -0
  196. package/dashboard/assets/operations-D8nUP5_m.js +4 -0
  197. package/dashboard/assets/operations-app-CQQhG54n.js +2 -0
  198. package/dashboard/assets/overview-page-DTGS8dPo.js +1 -0
  199. package/dashboard/assets/page-header-MFVvEtZW.js +1 -0
  200. package/dashboard/assets/play-Dwo-9xt6.js +1 -0
  201. package/dashboard/assets/scans-page-ChVtq8Us.js +1 -0
  202. package/dashboard/assets/search-CiooTLck.js +1 -0
  203. package/dashboard/assets/siren-CCBwTSuk.js +1 -0
  204. package/dashboard/assets/table-BYS-nIVA.js +1 -0
  205. package/dashboard/assets/tabs-DivxbhQy.js +1 -0
  206. package/dashboard/desktop.html +21 -0
  207. package/dashboard/index.html +15 -0
  208. package/package.json +30 -18
  209. package/bin/0sec.cjs +0 -361
@@ -0,0 +1,542 @@
1
+ #!/usr/bin/env node
2
+ import { createRequire as __0secCreateRequire } from "node:module";
3
+ const require = __0secCreateRequire(import.meta.url);
4
+ import {
5
+ AD_ANALYZERS,
6
+ findAclAbuseChains,
7
+ findAdcsEscalation,
8
+ findDcsyncPrincipals,
9
+ findKerberoastablePaths,
10
+ findPathsToDomainAdmin,
11
+ findUnconstrainedDelegation
12
+ } from "./chunk-VQG4FT5D.js";
13
+
14
+ // packages/core/dist/adgraph/ingest.js
15
+ var FILE_TYPE_TO_NODE_KIND = {
16
+ users: "User",
17
+ computers: "Computer",
18
+ groups: "Group",
19
+ domains: "Domain",
20
+ gpos: "GPO",
21
+ ous: "OU",
22
+ containers: "Container",
23
+ certtemplates: "CertTemplate",
24
+ enterprisecas: "EnterpriseCA",
25
+ rootcas: "RootCA",
26
+ aiacas: "AIACA",
27
+ ntauthstores: "NTAuthStore",
28
+ issuancepolicies: "IssuancePolicy"
29
+ };
30
+ var ACE_RIGHT_ALIASES = {
31
+ owner: "Owns",
32
+ all: "GenericAll",
33
+ extendedright: "AllExtendedRights",
34
+ "ds-replication-get-changes": "GetChanges",
35
+ "ds-replication-get-changes-all": "GetChangesAll",
36
+ "ds-replication-get-changes-in-filtered-set": "GetChangesInFilteredSet",
37
+ "user-force-change-password": "ForceChangePassword"
38
+ };
39
+ var PRINCIPAL_TO_COMPUTER_COLLECTIONS = [
40
+ ["LocalAdmins", "AdminTo"],
41
+ ["RemoteDesktopUsers", "CanRDP"],
42
+ ["DcomUsers", "ExecuteDCOM"],
43
+ ["PSRemoteUsers", "CanPSRemote"],
44
+ ["AllowedToAct", "AllowedToAct"]
45
+ ];
46
+ function isRecord(value) {
47
+ return typeof value === "object" && value !== null && !Array.isArray(value);
48
+ }
49
+ function asString(value) {
50
+ if (typeof value === "string" && value.trim().length > 0)
51
+ return value.trim();
52
+ return void 0;
53
+ }
54
+ function asArray(value) {
55
+ return Array.isArray(value) ? value : [];
56
+ }
57
+ function readResultList(value) {
58
+ if (Array.isArray(value))
59
+ return value;
60
+ if (isRecord(value))
61
+ return asArray(value.Results ?? value.results);
62
+ return [];
63
+ }
64
+ function field(record, ...names) {
65
+ for (const name of names) {
66
+ if (name in record)
67
+ return record[name];
68
+ const lower = name.toLowerCase();
69
+ for (const key of Object.keys(record)) {
70
+ if (key.toLowerCase() === lower)
71
+ return record[key];
72
+ }
73
+ }
74
+ return void 0;
75
+ }
76
+ function normalizeProperties(value) {
77
+ if (!isRecord(value))
78
+ return {};
79
+ const out = {};
80
+ for (const [key, raw] of Object.entries(value)) {
81
+ out[key.toLowerCase()] = raw;
82
+ }
83
+ return out;
84
+ }
85
+ function normalizeObjectId(value) {
86
+ const id = asString(value);
87
+ return id ? id.toUpperCase() : void 0;
88
+ }
89
+ function normalizeNodeKind(value, fallback) {
90
+ const kind = asString(value);
91
+ if (!kind)
92
+ return fallback;
93
+ if (kind.toLowerCase() === "base")
94
+ return fallback;
95
+ return kind;
96
+ }
97
+ function normalizeEdgeKind(value) {
98
+ const kind = asString(value);
99
+ if (!kind)
100
+ return void 0;
101
+ return ACE_RIGHT_ALIASES[kind.toLowerCase()] ?? kind;
102
+ }
103
+ var ChunkBuilder = class {
104
+ nodes = [];
105
+ edges = [];
106
+ warnings = [];
107
+ node(node) {
108
+ this.nodes.push(node);
109
+ }
110
+ /**
111
+ * Reference to an object we may not have collected. Emitted as a stub node so
112
+ * traversal never dead-ends on a member SID whose own file is missing; a real
113
+ * record for the same id wins during {@link buildAdGraph} merge.
114
+ */
115
+ reference(objectId, kind, label) {
116
+ this.nodes.push({
117
+ objectId,
118
+ label: label ?? objectId,
119
+ kind,
120
+ properties: {},
121
+ stub: true
122
+ });
123
+ }
124
+ edge(source, target, kind, properties) {
125
+ this.edges.push(properties ? { source, target, kind, properties } : { source, target, kind });
126
+ }
127
+ warn(message) {
128
+ if (this.warnings.length < 200)
129
+ this.warnings.push(message);
130
+ }
131
+ };
132
+ function readReference(builder, value, fallbackKind, idFields = ["ObjectIdentifier"]) {
133
+ if (typeof value === "string") {
134
+ const id2 = normalizeObjectId(value);
135
+ if (id2)
136
+ builder.reference(id2, fallbackKind);
137
+ return id2;
138
+ }
139
+ if (!isRecord(value))
140
+ return void 0;
141
+ const id = normalizeObjectId(field(value, ...idFields));
142
+ if (!id)
143
+ return void 0;
144
+ builder.reference(id, normalizeNodeKind(field(value, "ObjectType", "kind"), fallbackKind));
145
+ return id;
146
+ }
147
+ function parseCollectorObject(builder, raw, defaultKind, index, sourceType) {
148
+ if (!isRecord(raw)) {
149
+ builder.warn(`${sourceType}[${index}]: not an object, skipped`);
150
+ return;
151
+ }
152
+ const objectId = normalizeObjectId(field(raw, "ObjectIdentifier", "objectid"));
153
+ if (!objectId) {
154
+ builder.warn(`${sourceType}[${index}]: missing ObjectIdentifier, skipped`);
155
+ return;
156
+ }
157
+ const properties = normalizeProperties(field(raw, "Properties"));
158
+ const label = asString(properties.name) ?? asString(properties.distinguishedname) ?? objectId;
159
+ const domainSid = normalizeObjectId(properties.domainsid) ?? (defaultKind === "Domain" ? objectId : void 0);
160
+ builder.node({
161
+ objectId,
162
+ label,
163
+ kind: normalizeNodeKind(field(raw, "ObjectType"), defaultKind),
164
+ ...domainSid ? { domainSid } : {},
165
+ properties
166
+ });
167
+ parseAces(builder, raw, objectId, sourceType, index);
168
+ parseMembership(builder, raw, objectId);
169
+ parseComputerCollections(builder, raw, objectId);
170
+ parseDelegation(builder, raw, objectId);
171
+ parseContainment(builder, raw, objectId, defaultKind);
172
+ parseTrusts(builder, raw, objectId);
173
+ }
174
+ function parseAces(builder, raw, objectId, sourceType, index) {
175
+ for (const ace of asArray(field(raw, "Aces"))) {
176
+ if (!isRecord(ace))
177
+ continue;
178
+ const principal = normalizeObjectId(field(ace, "PrincipalSID", "principalsid"));
179
+ const kind = normalizeEdgeKind(field(ace, "RightName", "rightname"));
180
+ if (!principal || !kind) {
181
+ builder.warn(`${sourceType}[${index}]: ACE missing PrincipalSID or RightName, skipped`);
182
+ continue;
183
+ }
184
+ builder.reference(principal, normalizeNodeKind(field(ace, "PrincipalType"), "Base"));
185
+ builder.edge(principal, objectId, kind, { isinherited: field(ace, "IsInherited") === true });
186
+ }
187
+ }
188
+ function parseMembership(builder, raw, objectId) {
189
+ for (const member of readResultList(field(raw, "Members"))) {
190
+ const memberId = readReference(builder, member, "Base");
191
+ if (memberId)
192
+ builder.edge(memberId, objectId, "MemberOf");
193
+ }
194
+ const primaryGroup = normalizeObjectId(field(raw, "PrimaryGroupSID"));
195
+ if (primaryGroup) {
196
+ builder.reference(primaryGroup, "Group");
197
+ builder.edge(objectId, primaryGroup, "MemberOf");
198
+ }
199
+ for (const sidHistory of readResultList(field(raw, "HasSIDHistory"))) {
200
+ const targetId = readReference(builder, sidHistory, "Base");
201
+ if (targetId)
202
+ builder.edge(objectId, targetId, "HasSIDHistory");
203
+ }
204
+ }
205
+ function parseComputerCollections(builder, raw, objectId) {
206
+ for (const [name, kind] of PRINCIPAL_TO_COMPUTER_COLLECTIONS) {
207
+ for (const entry of readResultList(field(raw, name))) {
208
+ const principalId = readReference(builder, entry, "Base");
209
+ if (principalId)
210
+ builder.edge(principalId, objectId, kind);
211
+ }
212
+ }
213
+ for (const session of readResultList(field(raw, "Sessions", "PrivilegedSessions", "RegistrySessions"))) {
214
+ if (!isRecord(session))
215
+ continue;
216
+ const userSid = normalizeObjectId(field(session, "UserSID"));
217
+ const computerSid = normalizeObjectId(field(session, "ComputerSID")) ?? objectId;
218
+ if (!userSid)
219
+ continue;
220
+ builder.reference(userSid, "User");
221
+ builder.reference(computerSid, "Computer");
222
+ builder.edge(computerSid, userSid, "HasSession");
223
+ }
224
+ for (const smsa of readResultList(field(raw, "DumpSMSAPassword"))) {
225
+ const principalId = readReference(builder, smsa, "User");
226
+ if (principalId)
227
+ builder.edge(objectId, principalId, "DumpSMSAPassword");
228
+ }
229
+ }
230
+ function parseDelegation(builder, raw, objectId) {
231
+ for (const target of readResultList(field(raw, "AllowedToDelegate"))) {
232
+ const targetId = readReference(builder, target, "Computer");
233
+ if (targetId)
234
+ builder.edge(objectId, targetId, "AllowedToDelegate");
235
+ }
236
+ for (const spnTarget of asArray(field(raw, "SPNTargets"))) {
237
+ if (!isRecord(spnTarget))
238
+ continue;
239
+ const computerSid = normalizeObjectId(field(spnTarget, "ComputerSID"));
240
+ if (!computerSid)
241
+ continue;
242
+ const service = asString(field(spnTarget, "Service")) ?? "";
243
+ if (service.toLowerCase() !== "sqladmin")
244
+ continue;
245
+ builder.reference(computerSid, "Computer");
246
+ builder.edge(objectId, computerSid, "SQLAdmin", { port: field(spnTarget, "Port") });
247
+ }
248
+ }
249
+ function parseContainment(builder, raw, objectId, defaultKind) {
250
+ for (const child of readResultList(field(raw, "ChildObjects"))) {
251
+ const childId = readReference(builder, child, "Base");
252
+ if (childId)
253
+ builder.edge(objectId, childId, "Contains");
254
+ }
255
+ for (const link of readResultList(field(raw, "Links"))) {
256
+ if (!isRecord(link))
257
+ continue;
258
+ const gpoId = normalizeObjectId(field(link, "Guid", "GUID", "ObjectIdentifier"));
259
+ if (!gpoId)
260
+ continue;
261
+ builder.reference(gpoId, "GPO");
262
+ builder.edge(gpoId, objectId, "GPLink", { isenforced: field(link, "IsEnforced") === true });
263
+ }
264
+ if (defaultKind === "Computer") {
265
+ const containedBy = field(raw, "ContainedBy");
266
+ const parentId = readReference(builder, containedBy, "Container");
267
+ if (parentId)
268
+ builder.edge(parentId, objectId, "Contains");
269
+ }
270
+ }
271
+ function parseTrusts(builder, raw, objectId) {
272
+ for (const trust of asArray(field(raw, "Trusts"))) {
273
+ if (!isRecord(trust))
274
+ continue;
275
+ const targetSid = normalizeObjectId(field(trust, "TargetDomainSid"));
276
+ if (!targetSid)
277
+ continue;
278
+ builder.reference(targetSid, "Domain", asString(field(trust, "TargetDomainName")));
279
+ const direction = Number(field(trust, "TrustDirection") ?? 0);
280
+ const properties = {
281
+ istransitive: field(trust, "IsTransitive") === true,
282
+ sidfilteringenabled: field(trust, "SidFilteringEnabled") === true,
283
+ trusttype: field(trust, "TrustType")
284
+ };
285
+ if (direction === 1 || direction === 3)
286
+ builder.edge(objectId, targetSid, "TrustedBy", properties);
287
+ if (direction === 2 || direction === 3)
288
+ builder.edge(targetSid, objectId, "TrustedBy", properties);
289
+ }
290
+ }
291
+ function parseGraphExport(builder, nodesRaw, edgesRaw) {
292
+ const byGraphId = /* @__PURE__ */ new Map();
293
+ for (const [graphId, value] of Object.entries(nodesRaw)) {
294
+ if (!isRecord(value))
295
+ continue;
296
+ const objectId = normalizeObjectId(field(value, "objectId", "ObjectIdentifier", "objectid")) ?? graphId.toUpperCase();
297
+ byGraphId.set(graphId, objectId);
298
+ builder.node({
299
+ objectId,
300
+ label: asString(field(value, "label", "name")) ?? objectId,
301
+ kind: normalizeNodeKind(field(value, "kind", "ObjectType"), "Base"),
302
+ properties: normalizeProperties(field(value, "properties", "Properties"))
303
+ });
304
+ }
305
+ for (const [index, value] of edgesRaw.entries()) {
306
+ if (!isRecord(value))
307
+ continue;
308
+ const kind = normalizeEdgeKind(field(value, "kind", "label", "RightName"));
309
+ const rawSource = asString(field(value, "source"));
310
+ const rawTarget = asString(field(value, "target"));
311
+ if (!kind || !rawSource || !rawTarget) {
312
+ builder.warn(`graph export edge[${index}]: missing source, target or kind, skipped`);
313
+ continue;
314
+ }
315
+ const source = byGraphId.get(rawSource) ?? rawSource.toUpperCase();
316
+ const target = byGraphId.get(rawTarget) ?? rawTarget.toUpperCase();
317
+ builder.reference(source, "Base");
318
+ builder.reference(target, "Base");
319
+ builder.edge(source, target, kind);
320
+ }
321
+ }
322
+ function parseBloodHoundFile(raw) {
323
+ const builder = new ChunkBuilder();
324
+ if (!isRecord(raw)) {
325
+ builder.warn("file is not a JSON object, skipped");
326
+ return { nodes: [], edges: [], warnings: builder.warnings };
327
+ }
328
+ const meta = isRecord(raw.meta) ? raw.meta : {};
329
+ const sourceType = asString(meta.type)?.toLowerCase();
330
+ const versionValue = Number(meta.version);
331
+ const collectorVersion = Number.isFinite(versionValue) ? versionValue : void 0;
332
+ const data = raw.data ?? raw.Data;
333
+ if (isRecord(data) && (isRecord(data.nodes) || Array.isArray(data.edges))) {
334
+ parseGraphExport(builder, isRecord(data.nodes) ? data.nodes : {}, asArray(data.edges));
335
+ return {
336
+ nodes: builder.nodes,
337
+ edges: builder.edges,
338
+ sourceType: sourceType ?? "graph-export",
339
+ collectorVersion,
340
+ warnings: builder.warnings
341
+ };
342
+ }
343
+ if (!Array.isArray(data)) {
344
+ builder.warn(`file has no usable "data" array (meta.type=${sourceType ?? "unknown"})`);
345
+ return { nodes: [], edges: [], sourceType, collectorVersion, warnings: builder.warnings };
346
+ }
347
+ const defaultKind = (sourceType && FILE_TYPE_TO_NODE_KIND[sourceType]) ?? "Base";
348
+ if (sourceType && !FILE_TYPE_TO_NODE_KIND[sourceType]) {
349
+ builder.warn(`unknown collector type "${sourceType}", nodes kept with ObjectType fallback`);
350
+ }
351
+ for (const [index, entry] of data.entries()) {
352
+ parseCollectorObject(builder, entry, defaultKind, index, sourceType ?? "unknown");
353
+ }
354
+ return {
355
+ nodes: builder.nodes,
356
+ edges: builder.edges,
357
+ sourceType,
358
+ collectorVersion,
359
+ warnings: builder.warnings
360
+ };
361
+ }
362
+ function buildAdGraph(nodes, edges, meta = {}) {
363
+ const nodeMap = /* @__PURE__ */ new Map();
364
+ for (const node of nodes) {
365
+ if (!node.objectId)
366
+ continue;
367
+ const existing = nodeMap.get(node.objectId);
368
+ if (!existing) {
369
+ nodeMap.set(node.objectId, node);
370
+ continue;
371
+ }
372
+ if (existing.stub && !node.stub) {
373
+ nodeMap.set(node.objectId, node);
374
+ continue;
375
+ }
376
+ if (existing.kind === "Base" && node.kind !== "Base")
377
+ existing.kind = node.kind;
378
+ if (existing.label === existing.objectId && node.label !== node.objectId)
379
+ existing.label = node.label;
380
+ if (!existing.domainSid && node.domainSid)
381
+ existing.domainSid = node.domainSid;
382
+ if (existing.stub && node.stub && Object.keys(node.properties).length > 0) {
383
+ existing.properties = { ...node.properties, ...existing.properties };
384
+ }
385
+ }
386
+ const outbound = /* @__PURE__ */ new Map();
387
+ const inbound = /* @__PURE__ */ new Map();
388
+ const edgesByKind = /* @__PURE__ */ new Map();
389
+ const dedupedEdges = [];
390
+ const seenEdges = /* @__PURE__ */ new Set();
391
+ const push = (index, key, value) => {
392
+ const bucket = index.get(key);
393
+ if (bucket)
394
+ bucket.push(value);
395
+ else
396
+ index.set(key, [value]);
397
+ };
398
+ for (const edge of edges) {
399
+ if (!edge.source || !edge.target || !edge.kind)
400
+ continue;
401
+ const key = `${edge.source}\0${edge.kind}\0${edge.target}`;
402
+ if (seenEdges.has(key))
403
+ continue;
404
+ seenEdges.add(key);
405
+ if (!nodeMap.has(edge.source)) {
406
+ nodeMap.set(edge.source, { objectId: edge.source, label: edge.source, kind: "Base", properties: {}, stub: true });
407
+ }
408
+ if (!nodeMap.has(edge.target)) {
409
+ nodeMap.set(edge.target, { objectId: edge.target, label: edge.target, kind: "Base", properties: {}, stub: true });
410
+ }
411
+ const index = dedupedEdges.length;
412
+ dedupedEdges.push(edge);
413
+ push(outbound, edge.source, index);
414
+ push(inbound, edge.target, index);
415
+ push(edgesByKind, edge.kind, index);
416
+ }
417
+ const nodesByKind = /* @__PURE__ */ new Map();
418
+ for (const node of nodeMap.values())
419
+ push(nodesByKind, node.kind, node.objectId);
420
+ return {
421
+ nodes: nodeMap,
422
+ edges: dedupedEdges,
423
+ outbound,
424
+ inbound,
425
+ nodesByKind,
426
+ edgesByKind,
427
+ meta: {
428
+ sourceTypes: meta.sourceTypes ?? [],
429
+ collectorVersion: meta.collectorVersion,
430
+ nodeCount: nodeMap.size,
431
+ edgeCount: dedupedEdges.length,
432
+ warnings: meta.warnings ?? [],
433
+ ingestedAt: meta.ingestedAt ?? (/* @__PURE__ */ new Date()).toISOString()
434
+ }
435
+ };
436
+ }
437
+ function ingestBloodHoundFiles(files) {
438
+ const nodes = [];
439
+ const edges = [];
440
+ const warnings = [];
441
+ const sourceTypes = [];
442
+ let collectorVersion;
443
+ for (const [index, file] of files.entries()) {
444
+ const chunk = parseBloodHoundFile(file);
445
+ nodes.push(...chunk.nodes);
446
+ edges.push(...chunk.edges);
447
+ for (const warning of chunk.warnings)
448
+ warnings.push(`file[${index}]: ${warning}`);
449
+ if (chunk.sourceType && !sourceTypes.includes(chunk.sourceType))
450
+ sourceTypes.push(chunk.sourceType);
451
+ if (chunk.collectorVersion !== void 0) {
452
+ collectorVersion = Math.max(collectorVersion ?? 0, chunk.collectorVersion);
453
+ }
454
+ }
455
+ return buildAdGraph(nodes, edges, { sourceTypes, collectorVersion, warnings });
456
+ }
457
+ function ingestBloodHoundJson(texts) {
458
+ const parsed = [];
459
+ const parseErrors = [];
460
+ for (const [index, text] of texts.entries()) {
461
+ try {
462
+ parsed.push(JSON.parse(text));
463
+ } catch (error) {
464
+ parseErrors.push(`file[${index}]: invalid JSON (${error.message})`);
465
+ }
466
+ }
467
+ const graph = ingestBloodHoundFiles(parsed);
468
+ graph.meta.warnings = [...parseErrors, ...graph.meta.warnings];
469
+ return graph;
470
+ }
471
+
472
+ // packages/core/dist/adgraph/index.js
473
+ var SEVERITY_RANK = { info: 1, low: 2, medium: 3, high: 4, critical: 5 };
474
+ function summarize(findings) {
475
+ const principals = /* @__PURE__ */ new Set();
476
+ const analyzersFired = /* @__PURE__ */ new Set();
477
+ let topSeverity = "info";
478
+ let criticalCount = 0;
479
+ let highCount = 0;
480
+ let mediumCount = 0;
481
+ let lowCount = 0;
482
+ for (const item of findings) {
483
+ analyzersFired.add(item.analyzer);
484
+ for (const principal of item.affectedPrincipals)
485
+ principals.add(principal);
486
+ if (SEVERITY_RANK[item.severity] > SEVERITY_RANK[topSeverity])
487
+ topSeverity = item.severity;
488
+ if (item.severity === "critical")
489
+ criticalCount += 1;
490
+ else if (item.severity === "high")
491
+ highCount += 1;
492
+ else if (item.severity === "medium")
493
+ mediumCount += 1;
494
+ else if (item.severity === "low")
495
+ lowCount += 1;
496
+ }
497
+ return {
498
+ findingCount: findings.length,
499
+ criticalCount,
500
+ highCount,
501
+ mediumCount,
502
+ lowCount,
503
+ topSeverity,
504
+ analyzersFired: [...analyzersFired],
505
+ affectedPrincipalCount: principals.size
506
+ };
507
+ }
508
+ function runAdGraphAnalysis(graph, opts = {}) {
509
+ const findings = [];
510
+ const warnings = [...graph.meta.warnings];
511
+ for (const analyzer of AD_ANALYZERS) {
512
+ try {
513
+ findings.push(...analyzer(graph, opts));
514
+ } catch (error) {
515
+ warnings.push(`analyzer ${analyzer.name} failed: ${error.message}`);
516
+ }
517
+ }
518
+ findings.sort((a, b) => SEVERITY_RANK[b.severity] - SEVERITY_RANK[a.severity] || (a.paths[0]?.length ?? Number.MAX_SAFE_INTEGER) - (b.paths[0]?.length ?? Number.MAX_SAFE_INTEGER) || a.id.localeCompare(b.id));
519
+ return {
520
+ generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
521
+ graph: { ...graph.meta, warnings },
522
+ summary: summarize(findings),
523
+ findings
524
+ };
525
+ }
526
+ var AD_ANALYZERS_BY_ID = {
527
+ "paths-to-domain-admin": findPathsToDomainAdmin,
528
+ "kerberoastable-paths": findKerberoastablePaths,
529
+ "unconstrained-delegation": findUnconstrainedDelegation,
530
+ "dcsync-principals": findDcsyncPrincipals,
531
+ "acl-abuse-chains": findAclAbuseChains,
532
+ "adcs-escalation": findAdcsEscalation
533
+ };
534
+
535
+ export {
536
+ parseBloodHoundFile,
537
+ buildAdGraph,
538
+ ingestBloodHoundFiles,
539
+ ingestBloodHoundJson,
540
+ runAdGraphAnalysis,
541
+ AD_ANALYZERS_BY_ID
542
+ };