0sec-cli 0.15.0 → 0.18.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 +327 -0
  2. package/README.md +68 -48
  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-SMH6V4PD.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-HQ7HLP6V.js +34 -0
  59. package/chunks/assumption-mining-5SNIVVDN.js +79 -0
  60. package/chunks/chunk-242TMK6G.js +110 -0
  61. package/chunks/chunk-2JCCA2JL.js +381 -0
  62. package/chunks/chunk-2RMLOJVB.js +47 -0
  63. package/chunks/chunk-3KPWWJCI.js +1422 -0
  64. package/chunks/chunk-3MOLBTLS.js +953 -0
  65. package/chunks/chunk-53G27VPS.js +136 -0
  66. package/chunks/chunk-57ZENEX2.js +169 -0
  67. package/chunks/chunk-5G3ZXFBW.js +182 -0
  68. package/chunks/chunk-5JI7L7KV.js +74240 -0
  69. package/chunks/chunk-6L26OBWI.js +1094 -0
  70. package/chunks/chunk-6LKRLK2R.js +542 -0
  71. package/chunks/chunk-72CISA2D.js +2597 -0
  72. package/chunks/chunk-7DQEV5QI.js +287 -0
  73. package/chunks/chunk-AD7WXDH6.js +3250 -0
  74. package/chunks/chunk-ADOLI6DT.js +102 -0
  75. package/chunks/chunk-AHTBZC3E.js +596 -0
  76. package/chunks/chunk-ASUR522M.js +518 -0
  77. package/chunks/chunk-ATATQACO.js +471 -0
  78. package/chunks/chunk-BATRQBOR.js +1732 -0
  79. package/chunks/chunk-BFR2CDV5.js +5735 -0
  80. package/chunks/chunk-BFRB6HB2.js +235 -0
  81. package/chunks/chunk-BKZFDZ23.js +361 -0
  82. package/chunks/chunk-BVAZO4WA.js +193 -0
  83. package/chunks/chunk-BZNEY2ZS.js +33225 -0
  84. package/chunks/chunk-C2WXWFBB.js +1070 -0
  85. package/chunks/chunk-CMKXP5RR.js +917 -0
  86. package/chunks/chunk-DW5UWPFY.js +275 -0
  87. package/chunks/chunk-F3WBKITT.js +687 -0
  88. package/chunks/chunk-GMT2AZKM.js +2439 -0
  89. package/chunks/chunk-H2FFLZNK.js +3 -0
  90. package/chunks/chunk-IOL7D5YV.js +515 -0
  91. package/chunks/chunk-IR537GON.js +49 -0
  92. package/chunks/chunk-JQHOLLTD.js +3729 -0
  93. package/chunks/chunk-KLTNTE2Z.js +121 -0
  94. package/chunks/chunk-LP3HHYQU.js +245 -0
  95. package/chunks/chunk-MYVT64FN.js +16 -0
  96. package/chunks/chunk-N7BOUYEV.js +852 -0
  97. package/chunks/chunk-OEFNRYI2.js +150 -0
  98. package/chunks/chunk-P6WKNFWX.js +1968 -0
  99. package/chunks/chunk-QI233I24.js +333 -0
  100. package/chunks/chunk-RJWOYEOG.js +271 -0
  101. package/chunks/chunk-RRMJC3ZE.js +105 -0
  102. package/chunks/chunk-RWONANDA.js +973 -0
  103. package/chunks/chunk-SAFFWQW4.js +5921 -0
  104. package/chunks/chunk-SF4KZ4O3.js +502 -0
  105. package/chunks/chunk-SVJEDVYK.js +808 -0
  106. package/chunks/chunk-TSK2AG6J.js +5108 -0
  107. package/chunks/chunk-U5FLXGHT.js +2010 -0
  108. package/chunks/chunk-UCYRA73C.js +662 -0
  109. package/chunks/chunk-UR4ELX2Y.js +4784 -0
  110. package/chunks/chunk-VQG4FT5D.js +685 -0
  111. package/chunks/chunk-WEBMRWEG.js +9337 -0
  112. package/chunks/chunk-WU6AFRAZ.js +1167 -0
  113. package/chunks/chunk-WVTBZEQO.js +1531 -0
  114. package/chunks/chunk-WXQ6BJ6A.js +596 -0
  115. package/chunks/chunk-XM5NLHYU.js +600 -0
  116. package/chunks/chunk-YLMN3N25.js +4054 -0
  117. package/chunks/chunk-YYRBQVFE.js +2572 -0
  118. package/chunks/chunk-Z5FA2XOX.js +2798 -0
  119. package/chunks/commands-TBC2F5CE.js +16999 -0
  120. package/chunks/corpus-v1.json +403 -0
  121. package/chunks/cost-ledger-NU63MYZM.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-KFWOAUUB.js +16 -0
  127. package/chunks/disclose-EKTWSCGW.js +132 -0
  128. package/chunks/dist-4MAW5X6L.js +74 -0
  129. package/chunks/dist-4YICS2J2.js +2776 -0
  130. package/chunks/dist-FMGSR3DW.js +159 -0
  131. package/chunks/eval-runner-7ZF472KV.js +27 -0
  132. package/chunks/example-manifest.json +95 -0
  133. package/chunks/exploit-agent-45YQOHPJ.js +98 -0
  134. package/chunks/exploit-autoclimb-UZGEMGYT.js +81 -0
  135. package/chunks/exploit-climb-SG23KB2G.js +358 -0
  136. package/chunks/fix-IG7LYXH3.js +12 -0
  137. package/chunks/github-issues-MJ6OYOOU.js +157 -0
  138. package/chunks/harness-7ODOLOWU.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-MMKUOETU.js +38 -0
  142. package/chunks/identity-6ZAIIWOR.js +191 -0
  143. package/chunks/kernel-primitive-7U6CWHXD.js +44 -0
  144. package/chunks/kernel-vm-runner-3JAU4O6J.js +62 -0
  145. package/chunks/memsafety-scan-J7SECV5W.js +16 -0
  146. package/chunks/native-loop-RJCJPOUS.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-OC2VZN2X.js +62 -0
  150. package/chunks/pipeline-BZK5BLJR.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-LQRCS5OY.js +13 -0
  154. package/chunks/replay-runner-45G3VU7X.js +39 -0
  155. package/chunks/run-D56MPDKY.js +32716 -0
  156. package/chunks/runtime-G7YWIO3B.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-GZ4A4KYT.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-YERCYMPD.js +13 -0
  164. package/chunks/web-recon-prepass-JJGPEOLE.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,471 @@
1
+ #!/usr/bin/env node
2
+ import { createRequire as __0secCreateRequire } from "node:module";
3
+ const require = __0secCreateRequire(import.meta.url);
4
+ import {
5
+ eventBus,
6
+ isCloudEventSinkActive
7
+ } from "./chunk-ADOLI6DT.js";
8
+
9
+ // packages/core/dist/runtime/process.js
10
+ import { spawn } from "node:child_process";
11
+ import { tmpdir } from "node:os";
12
+ import { join, resolve } from "node:path";
13
+ import { writeFileSync } from "node:fs";
14
+ var dim = (text) => `\x1B[2m${text}\x1B[0m`;
15
+ function formatToolDetail(input) {
16
+ const inp = input;
17
+ if (inp?.file_path)
18
+ return String(inp.file_path).split("/").slice(-2).join("/");
19
+ if (inp?.command)
20
+ return String(inp.command).slice(0, 60);
21
+ if (inp?.pattern)
22
+ return String(inp.pattern).slice(0, 40);
23
+ if (inp?.path)
24
+ return String(inp.path).slice(0, 60);
25
+ if (inp?.content)
26
+ return "(writing file)";
27
+ return "";
28
+ }
29
+ function friendlyToolName(name) {
30
+ const stripped = name.replace(/^mcp__\w+__/, "");
31
+ return stripped.split("_").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
32
+ }
33
+ function showToolCall(onToolCall, name, input) {
34
+ const rawName = name || "tool";
35
+ if (/^(ToolSearch|Read|Glob|Grep|Write|Edit|Bash|LSP|Agent)$/i.test(rawName))
36
+ return;
37
+ const toolName = friendlyToolName(rawName);
38
+ const detail = formatToolDetail(input);
39
+ if (onToolCall) {
40
+ onToolCall(toolName, detail);
41
+ }
42
+ if (process.stderr.isTTY && !onToolCall) {
43
+ process.stderr.write(dim(` ${toolName}${detail ? ": " + detail : ""}
44
+ `));
45
+ }
46
+ }
47
+ var RUNTIME_COMMANDS = {
48
+ claude: "claude",
49
+ codex: "codex",
50
+ gemini: "gemini"
51
+ };
52
+ function resolveCliEntrypoint() {
53
+ return resolve(process.argv[1] ?? join(process.cwd(), "dist", "index.js"));
54
+ }
55
+ function buildOsecMcpCommandArgs(context) {
56
+ const cliEntrypoint = resolveCliEntrypoint();
57
+ const args = [
58
+ cliEntrypoint,
59
+ "mcp-server",
60
+ "--target",
61
+ context.target ?? "",
62
+ "--scan-id",
63
+ context.scanId ?? "no-scan-id"
64
+ ];
65
+ if (context.mcp?.dbPath) {
66
+ args.push("--db-path", context.mcp.dbPath);
67
+ }
68
+ if (context.mcp?.scopeFile) {
69
+ args.push("--scope", context.mcp.scopeFile);
70
+ }
71
+ if (context.mcp?.rateLimit) {
72
+ args.push("--rate-limit", context.mcp.rateLimit);
73
+ }
74
+ if (context.mcp?.allowScanners) {
75
+ args.push("--allow-scanners");
76
+ }
77
+ return args;
78
+ }
79
+ function numericField(obj, key) {
80
+ const v = obj[key];
81
+ if (typeof v === "number" && Number.isFinite(v))
82
+ return v;
83
+ if (typeof v === "string" && /^\d+$/.test(v))
84
+ return Number(v);
85
+ return void 0;
86
+ }
87
+ function safeJsonStringify(v) {
88
+ try {
89
+ return JSON.stringify(v) ?? "";
90
+ } catch {
91
+ return "(unserialisable)";
92
+ }
93
+ }
94
+ function buildClaudeMcpConfig(context) {
95
+ return JSON.stringify({
96
+ mcpServers: {
97
+ "0sec": {
98
+ command: process.execPath,
99
+ args: buildOsecMcpCommandArgs(context)
100
+ }
101
+ }
102
+ });
103
+ }
104
+ var ProcessRuntime = class {
105
+ type;
106
+ config;
107
+ command;
108
+ constructor(config) {
109
+ this.type = config.type;
110
+ this.config = config;
111
+ this.command = RUNTIME_COMMANDS[config.type] ?? config.type;
112
+ }
113
+ async execute(prompt, context) {
114
+ const start = Date.now();
115
+ const args = this.buildArgs(prompt, context);
116
+ const env = this.buildEnv(context);
117
+ const onToolCall = this.config.onToolCall;
118
+ const scanId = context?.scanId;
119
+ const emitScanEvents = this.type === "codex" && isCloudEventSinkActive();
120
+ const maxTurnsHint = 40;
121
+ let turnNumber = 0;
122
+ let toolCallSeq = 0;
123
+ let deltaSeq = 0;
124
+ let turnStartedAt = 0;
125
+ const toolCallStartedAt = /* @__PURE__ */ new Map();
126
+ const seenSequenceNumbers = /* @__PURE__ */ new Set();
127
+ const isSeenSequence = (event) => {
128
+ const seq = event.sequence_number;
129
+ if (typeof seq !== "number" && typeof seq !== "string")
130
+ return false;
131
+ const key = `${event.type ?? "?"}|${seq}`;
132
+ if (seenSequenceNumbers.has(key))
133
+ return true;
134
+ seenSequenceNumbers.add(key);
135
+ return false;
136
+ };
137
+ const emitCodexCloudEvents = (event) => {
138
+ if (isSeenSequence(event))
139
+ return;
140
+ const eventType = typeof event.type === "string" ? event.type : "";
141
+ switch (eventType) {
142
+ case "thread.started": {
143
+ eventBus.emit("llm_planner_invoked", {
144
+ turn: 0,
145
+ model: this.config.model,
146
+ role: "attack"
147
+ });
148
+ return;
149
+ }
150
+ case "turn.started": {
151
+ turnNumber += 1;
152
+ turnStartedAt = Date.now();
153
+ deltaSeq = 0;
154
+ eventBus.emit("agent_turn_started", {
155
+ turn: turnNumber,
156
+ max_turns: maxTurnsHint,
157
+ role: "attack"
158
+ });
159
+ eventBus.emit("llm_planner_invoked", {
160
+ turn: turnNumber,
161
+ model: this.config.model,
162
+ role: "attack"
163
+ });
164
+ return;
165
+ }
166
+ case "turn.completed": {
167
+ const usage = event.usage ?? {};
168
+ const inputTokens = numericField(usage, "input_tokens");
169
+ const cachedInputTokens = numericField(usage, "cached_input_tokens");
170
+ const outputTokens = numericField(usage, "output_tokens");
171
+ const reasoningTokens = numericField(usage, "reasoning_output_tokens");
172
+ const durationMs = turnStartedAt > 0 ? Date.now() - turnStartedAt : 0;
173
+ eventBus.emit("agent_turn_completed", {
174
+ turn: turnNumber,
175
+ duration_ms: durationMs,
176
+ reason: "continue",
177
+ role: "attack"
178
+ });
179
+ eventBus.emit("cost_update", {
180
+ turn: turnNumber,
181
+ cost_usd: 0,
182
+ input_tokens: inputTokens,
183
+ output_tokens: outputTokens,
184
+ token_input: inputTokens,
185
+ token_output: outputTokens,
186
+ cached_input_tokens: cachedInputTokens,
187
+ reasoning_output_tokens: reasoningTokens
188
+ });
189
+ return;
190
+ }
191
+ case "item.started": {
192
+ const item = event.item ?? {};
193
+ const itemType = typeof item.type === "string" ? item.type : "";
194
+ if (itemType === "command_execution" && typeof item.command === "string") {
195
+ toolCallSeq += 1;
196
+ toolCallStartedAt.set(toolCallSeq, Date.now());
197
+ eventBus.emit("tool_call_started", {
198
+ tool: "shell",
199
+ turn: turnNumber,
200
+ args_preview: item.command.slice(0, 200),
201
+ ts: Date.now()
202
+ });
203
+ } else if (itemType === "mcp_tool_call") {
204
+ toolCallSeq += 1;
205
+ toolCallStartedAt.set(toolCallSeq, Date.now());
206
+ const server = typeof item.server === "string" ? item.server : "?";
207
+ const tool = typeof item.tool === "string" ? item.tool : "?";
208
+ const argsRaw = item.arguments ?? {};
209
+ const argsPreview = typeof argsRaw === "string" ? argsRaw : safeJsonStringify(argsRaw);
210
+ eventBus.emit("tool_call_started", {
211
+ tool: `${server}__${tool}`,
212
+ turn: turnNumber,
213
+ args_preview: argsPreview.slice(0, 200),
214
+ ts: Date.now()
215
+ });
216
+ }
217
+ return;
218
+ }
219
+ case "item.completed": {
220
+ const item = event.item ?? {};
221
+ const itemType = typeof item.type === "string" ? item.type : "";
222
+ if (itemType === "command_execution") {
223
+ const startedAt = toolCallStartedAt.get(toolCallSeq);
224
+ const durationMs = startedAt != null ? Date.now() - startedAt : 0;
225
+ toolCallStartedAt.delete(toolCallSeq);
226
+ eventBus.emit("tool_call_completed", {
227
+ tool: "shell",
228
+ turn: turnNumber,
229
+ duration_ms: durationMs,
230
+ status: "ok",
231
+ ts: Date.now()
232
+ });
233
+ } else if (itemType === "mcp_tool_call") {
234
+ const startedAt = toolCallStartedAt.get(toolCallSeq);
235
+ const durationMs = startedAt != null ? Date.now() - startedAt : 0;
236
+ toolCallStartedAt.delete(toolCallSeq);
237
+ const server = typeof item.server === "string" ? item.server : "?";
238
+ const tool = typeof item.tool === "string" ? item.tool : "?";
239
+ const status = item.status === "success" || item.status === "completed" ? "ok" : "error";
240
+ const errorMsg = status === "error" ? typeof item.error === "string" ? item.error : safeJsonStringify(item.error ?? null) : void 0;
241
+ eventBus.emit("tool_call_completed", {
242
+ tool: `${server}__${tool}`,
243
+ turn: turnNumber,
244
+ duration_ms: durationMs,
245
+ status,
246
+ ...errorMsg ? { error: errorMsg.slice(0, 400) } : {},
247
+ ts: Date.now()
248
+ });
249
+ } else if (itemType === "function_call" || itemType === "tool_call") {
250
+ toolCallSeq += 1;
251
+ const toolName = typeof item.tool_name === "string" && item.tool_name || typeof item.name === "string" && item.name || "mcp_tool";
252
+ const argsField = item.arguments ?? item.input ?? "";
253
+ const detail = typeof argsField === "string" ? argsField : safeJsonStringify(argsField);
254
+ eventBus.emit("tool_call_started", {
255
+ tool: toolName,
256
+ turn: turnNumber,
257
+ args_preview: detail.slice(0, 200),
258
+ ts: Date.now()
259
+ });
260
+ eventBus.emit("tool_call_completed", {
261
+ tool: toolName,
262
+ turn: turnNumber,
263
+ duration_ms: 0,
264
+ status: "ok",
265
+ ts: Date.now()
266
+ });
267
+ } else if (itemType === "reasoning") {
268
+ const reasoningText = typeof item.text === "string" && item.text || typeof item.summary === "string" && item.summary || "";
269
+ if (reasoningText.length > 0) {
270
+ eventBus.emit("reasoning_summary", {
271
+ turn: turnNumber,
272
+ summary: reasoningText.slice(0, 2e3)
273
+ });
274
+ }
275
+ } else if (itemType === "agent_message") {
276
+ const messageText = typeof item.text === "string" ? item.text : "";
277
+ if (messageText.length > 0) {
278
+ deltaSeq += 1;
279
+ eventBus.emit("delta", {
280
+ turn: turnNumber,
281
+ scope: "assistant_response",
282
+ text: messageText.slice(0, 2e3),
283
+ seq: deltaSeq,
284
+ role: "attack"
285
+ });
286
+ }
287
+ }
288
+ return;
289
+ }
290
+ }
291
+ };
292
+ return new Promise((resolve2) => {
293
+ let stdout = "";
294
+ let stderr = "";
295
+ let resultText = "";
296
+ let timedOut = false;
297
+ const isJsonStream = args.includes("stream-json") || args.includes("--json");
298
+ const proc = spawn(this.command, args, {
299
+ cwd: this.config.cwd ?? process.cwd(),
300
+ env: { ...process.env, ...env },
301
+ stdio: ["ignore", "pipe", "pipe"]
302
+ });
303
+ proc.stdout.on("data", (chunk) => {
304
+ const text = chunk.toString();
305
+ stdout += text;
306
+ if (isJsonStream) {
307
+ for (const line of text.split("\n")) {
308
+ if (!line.trim())
309
+ continue;
310
+ try {
311
+ const event = JSON.parse(line);
312
+ if (event.type === "assistant" && event.message?.content) {
313
+ for (const block of event.message.content) {
314
+ if (block.type === "text") {
315
+ resultText += block.text;
316
+ this.config.onThinking?.(block.text);
317
+ } else if (block.type === "tool_use") {
318
+ showToolCall(onToolCall, block.name, block.input);
319
+ }
320
+ }
321
+ } else if (event.type === "result") {
322
+ resultText = event.result || resultText;
323
+ }
324
+ if (event.type === "item.started" && event.item?.type === "command_execution") {
325
+ showToolCall(onToolCall, "shell", { command: event.item.command });
326
+ }
327
+ if (event.type === "item.completed" && event.item) {
328
+ if (event.item.type === "agent_message" && event.item.text) {
329
+ resultText += event.item.text;
330
+ this.config.onThinking?.(event.item.text);
331
+ } else if (event.item.type === "command_execution" && event.item.command) {
332
+ }
333
+ }
334
+ if (emitScanEvents)
335
+ emitCodexCloudEvents(event);
336
+ } catch {
337
+ }
338
+ }
339
+ }
340
+ });
341
+ proc.stderr.on("data", (chunk) => {
342
+ const text = chunk.toString();
343
+ stderr += text;
344
+ if (/permission|approve|allow.*tool/i.test(stderr) && stderr.length > 500) {
345
+ proc.kill("SIGTERM");
346
+ stderr += "\n[0sec] Subprocess killed: MCP tools require interactive approval. Use --runtime api instead.";
347
+ }
348
+ });
349
+ const timer = setTimeout(() => {
350
+ timedOut = true;
351
+ proc.kill("SIGTERM");
352
+ setTimeout(() => proc.kill("SIGKILL"), 5e3);
353
+ }, this.config.timeout);
354
+ proc.on("close", (code) => {
355
+ clearTimeout(timer);
356
+ const output = isJsonStream ? (resultText || stdout).trim() : stdout.trim();
357
+ resolve2({
358
+ output,
359
+ exitCode: code,
360
+ timedOut,
361
+ durationMs: Date.now() - start,
362
+ error: code !== 0 ? stderr.trim() || void 0 : void 0
363
+ });
364
+ });
365
+ proc.on("error", (err) => {
366
+ clearTimeout(timer);
367
+ resolve2({
368
+ output: "",
369
+ exitCode: 1,
370
+ timedOut: false,
371
+ durationMs: Date.now() - start,
372
+ error: err.message
373
+ });
374
+ });
375
+ });
376
+ }
377
+ async isAvailable() {
378
+ const attempt = (timeoutMs) => new Promise((resolve2) => {
379
+ const proc = spawn(this.command, ["--version"], {
380
+ stdio: ["pipe", "pipe", "pipe"]
381
+ });
382
+ let settled = false;
383
+ const finish = (ok) => {
384
+ if (settled)
385
+ return;
386
+ settled = true;
387
+ resolve2(ok);
388
+ };
389
+ proc.on("close", (code) => finish(code === 0));
390
+ proc.on("error", () => finish(false));
391
+ setTimeout(() => {
392
+ proc.kill();
393
+ finish(false);
394
+ }, timeoutMs).unref?.();
395
+ });
396
+ if (await attempt(5e3))
397
+ return true;
398
+ return attempt(15e3);
399
+ }
400
+ buildArgs(prompt, context) {
401
+ switch (this.type) {
402
+ case "claude": {
403
+ const args = ["-p", prompt, "--verbose", "--output-format", "stream-json"];
404
+ if (context?.mcp?.enableTargetTools && context.target && context.scanId) {
405
+ args.push("--mcp-config", buildClaudeMcpConfig(context), "--dangerously-skip-permissions");
406
+ }
407
+ if (context?.systemPrompt) {
408
+ args.push("--system-prompt", context.systemPrompt);
409
+ }
410
+ if (this.config.outputSchema) {
411
+ args.push("--json-schema", JSON.stringify(this.config.outputSchema));
412
+ }
413
+ return args;
414
+ }
415
+ case "codex": {
416
+ const args = [
417
+ "exec",
418
+ "--skip-git-repo-check",
419
+ "--json"
420
+ ];
421
+ if (this.config.model) {
422
+ args.push("--model", this.config.model);
423
+ }
424
+ if (context?.mcp?.enableTargetTools && context.target && context.scanId) {
425
+ throw new Error("Codex CLI MCP target tools are not supported. Use the direct ChatGPT Codex provider for live target scans.");
426
+ }
427
+ if (this.config.outputSchema) {
428
+ const schemaPath = join(tmpdir(), `0sec-schema-${Date.now()}.json`);
429
+ writeFileSync(schemaPath, JSON.stringify(this.config.outputSchema));
430
+ args.push("--output-schema", schemaPath);
431
+ }
432
+ args.push(prompt);
433
+ return args;
434
+ }
435
+ case "gemini": {
436
+ const args = ["-p", prompt, "--output-format", "stream-json"];
437
+ return args;
438
+ }
439
+ default:
440
+ return ["-p", prompt];
441
+ }
442
+ }
443
+ buildEnv(context) {
444
+ const env = {
445
+ ...this.config.env
446
+ };
447
+ if (context?.target) {
448
+ env["0SEC_TARGET"] = context.target;
449
+ }
450
+ if (context?.findings) {
451
+ env["0SEC_FINDINGS"] = context.findings;
452
+ }
453
+ if (context?.templateId) {
454
+ env["0SEC_TEMPLATE_ID"] = context.templateId;
455
+ }
456
+ if (context?.mcp?.auth) {
457
+ env["0SEC_MCP_AUTH_JSON"] = JSON.stringify(context.mcp.auth);
458
+ }
459
+ if (context?.mcp?.attributionHeaders) {
460
+ env["0SEC_MCP_ATTRIBUTION_HEADERS_JSON"] = JSON.stringify(context.mcp.attributionHeaders);
461
+ }
462
+ if (context?.mcp?.attributionUaToken) {
463
+ env["0SEC_MCP_ATTRIBUTION_UA_TOKEN"] = context.mcp.attributionUaToken;
464
+ }
465
+ return env;
466
+ }
467
+ };
468
+
469
+ export {
470
+ ProcessRuntime
471
+ };