opencode-api-security-testing 3.0.3 → 3.0.5

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-api-security-testing",
3
- "version": "3.0.3",
3
+ "version": "3.0.5",
4
4
  "description": "API Security Testing Plugin for OpenCode - Automated vulnerability scanning and penetration testing",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
@@ -9,14 +9,11 @@
9
9
  "agents/",
10
10
  "core/",
11
11
  "references/",
12
- "examples/",
13
12
  "SKILL.md",
14
- "postinstall.mjs",
15
- "preuninstall.mjs"
13
+ "postinstall.mjs"
16
14
  ],
17
15
  "scripts": {
18
- "postinstall": "node postinstall.mjs",
19
- "preuninstall": "node preuninstall.mjs"
16
+ "postinstall": "node postinstall.mjs"
20
17
  },
21
18
  "keywords": [
22
19
  "opencode",
package/postinstall.mjs CHANGED
@@ -4,17 +4,16 @@
4
4
  * postinstall.mjs - API Security Testing Plugin
5
5
  *
6
6
  * Installs:
7
- * 1. Agents to ~/.config/opencode/agents/
8
- * 2. Skill (SKILL.md) to ~/.config/opencode/skills/api-security-testing/
9
- * 3. References to ~/.config/opencode/skills/api-security-testing/
7
+ * 1. agents to ~/.config/opencode/agents/
8
+ * 2. SKILL.md and references to ~/.config/opencode/skills/api-security-testing/
10
9
  */
11
10
 
12
11
  import { copyFileSync, existsSync, mkdirSync, readdirSync } from "node:fs";
13
- import { join, dirname } from "node:path";
12
+ import { join } from "node:path";
14
13
  import { fileURLToPath } from "node:url";
15
14
 
16
15
  const __filename = fileURLToPath(import.meta.url);
17
- const __dirname = dirname(__filename);
16
+ const __dirname = join(__filename, "..");
18
17
 
19
18
  function getOpencodeBaseDir() {
20
19
  const home = process.env.HOME || process.env.USERPROFILE || "/root";
@@ -29,100 +28,90 @@ function main() {
29
28
 
30
29
  console.log("[api-security-testing] Installing...");
31
30
  console.log(` Package root: ${packageRoot}`);
32
- console.log(` Target base: ${getOpencodeBaseDir()}`);
33
31
 
34
- let successCount = 0;
35
- let totalFiles = 0;
32
+ let totalInstalled = 0;
33
+ let totalFailed = 0;
36
34
 
37
35
  // 1. Install agents
38
36
  console.log("\n[1/3] Installing agents...");
39
37
  if (existsSync(agentsSourceDir)) {
40
- const agentFiles = readdirSync(agentsSourceDir).filter(f => f.endsWith(".md"));
41
- totalFiles += agentFiles.length;
42
-
43
38
  if (!existsSync(agentsTargetDir)) {
44
39
  mkdirSync(agentsTargetDir, { recursive: true });
45
40
  }
46
41
 
47
- for (const file of agentFiles) {
48
- const sourcePath = join(agentsSourceDir, file);
49
- const targetPath = join(agentsTargetDir, file);
42
+ const files = readdirSync(agentsSourceDir).filter(f => f.endsWith(".md"));
43
+ for (const file of files) {
50
44
  try {
51
- copyFileSync(sourcePath, targetPath);
52
- console.log(` ✓ Installed agent: ${file}`);
53
- successCount++;
45
+ copyFileSync(join(agentsSourceDir, file), join(agentsTargetDir, file));
46
+ console.log(` ✓ ${file}`);
47
+ totalInstalled++;
54
48
  } catch (err) {
55
- console.error(` ✗ Failed: ${file} - ${err.message}`);
49
+ console.error(` ✗ ${file}: ${err.message}`);
50
+ totalFailed++;
56
51
  }
57
52
  }
58
- } else {
59
- console.error(" ✗ agents/ directory not found");
60
53
  }
61
54
 
62
55
  // 2. Install SKILL.md
63
- console.log("\n[2/3] Installing skill...");
56
+ console.log("\n[2/3] Installing SKILL.md...");
64
57
  const skillSource = join(packageRoot, "SKILL.md");
65
- const skillTarget = join(skillTargetDir, "SKILL.md");
66
- totalFiles++;
67
-
68
58
  if (existsSync(skillSource)) {
69
59
  if (!existsSync(skillTargetDir)) {
70
60
  mkdirSync(skillTargetDir, { recursive: true });
71
61
  }
72
62
  try {
73
- copyFileSync(skillSource, skillTarget);
74
- console.log(`Installed: SKILL.md`);
75
- successCount++;
63
+ copyFileSync(skillSource, join(skillTargetDir, "SKILL.md"));
64
+ console.log(" ✓ SKILL.md");
65
+ totalInstalled++;
76
66
  } catch (err) {
77
- console.error(` ✗ Failed: SKILL.md - ${err.message}`);
67
+ console.error(` ✗ SKILL.md: ${err.message}`);
68
+ totalFailed++;
78
69
  }
79
- } else {
80
- console.error(" ✗ SKILL.md not found");
81
70
  }
82
71
 
83
72
  // 3. Install references
84
73
  console.log("\n[3/3] Installing references...");
85
74
  const refsSourceDir = join(packageRoot, "references");
86
75
  const refsTargetDir = join(skillTargetDir, "references");
87
-
88
76
  if (existsSync(refsSourceDir)) {
89
77
  if (!existsSync(refsTargetDir)) {
90
78
  mkdirSync(refsTargetDir, { recursive: true });
91
79
  }
92
80
 
93
- const refFiles = readdirSync(refsSourceDir, { recursive: true }).filter(f => typeof f === "string");
94
- totalFiles += refFiles.length;
95
-
96
- for (const file of refFiles) {
97
- const sourcePath = join(refsSourceDir, file);
98
- const targetPath = join(refsTargetDir, file);
99
- const targetFileDir = join(refsTargetDir, file).replace(/\/[^\/]+$/, "");
100
- if (!existsSync(targetFileDir)) {
101
- mkdirSync(targetFileDir, { recursive: true });
102
- }
103
- try {
104
- copyFileSync(sourcePath, targetPath);
105
- console.log(` ✓ Installed: references/${file}`);
106
- successCount++;
107
- } catch (err) {
108
- console.error(` ✗ Failed: references/${file} - ${err.message}`);
81
+ function copyDir(src, dest) {
82
+ const items = readdirSync(src);
83
+ for (const item of items) {
84
+ const srcPath = join(src, item);
85
+ const destPath = join(dest, item);
86
+ try {
87
+ copyFileSync(srcPath, destPath);
88
+ totalInstalled++;
89
+ } catch {
90
+ if (existsSync(srcPath) && !srcPath.endsWith(".md")) {
91
+ mkdirSync(destPath, { recursive: true });
92
+ copyDir(srcPath, destPath);
93
+ }
94
+ }
109
95
  }
110
96
  }
111
- } else {
112
- console.log(" (references/ not found, skipping)");
97
+
98
+ try {
99
+ copyDir(refsSourceDir, refsTargetDir);
100
+ console.log(" ✓ references/");
101
+ totalInstalled++;
102
+ } catch (err) {
103
+ console.error(` ✗ references/: ${err.message}`);
104
+ totalFailed++;
105
+ }
113
106
  }
114
107
 
115
- // Summary
116
- console.log("\n========================================");
117
- if (successCount === totalFiles) {
118
- console.log(`✓ Successfully installed ${successCount} file(s)`);
119
- console.log(`\nAgent location: ${agentsTargetDir}`);
120
- console.log(`Skill location: ${skillTargetDir}`);
121
- console.log("\nTo use:");
122
- console.log(" @api-cyber-supervisor - Start security testing");
123
- console.log(" skill({ name: \"api-security-testing\" }) - Load skill");
108
+ console.log(`\n========================================`);
109
+ if (totalFailed === 0) {
110
+ console.log(`✓ Installed ${totalInstalled} file(s)`);
111
+ console.log(`\nAgents: ${agentsTargetDir}`);
112
+ console.log(`Skill: ${skillTargetDir}`);
124
113
  } else {
125
- console.log(`⚠ Partially installed: ${successCount}/${totalFiles}`);
114
+ console.log(`⚠ Installed ${totalInstalled}, failed ${totalFailed}`);
126
115
  process.exit(1);
127
116
  }
128
117
  }
package/src/index.ts CHANGED
@@ -1,168 +1,30 @@
1
1
  import type { Plugin } from "@opencode-ai/plugin";
2
2
  import { tool } from "@opencode-ai/plugin";
3
- import type { AgentConfig } from "@opencode-ai/sdk";
4
3
  import { join } from "path";
5
4
  import { existsSync } from "fs";
6
5
 
7
6
  const SKILL_DIR = "skills/api-security-testing";
8
7
  const CORE_DIR = `${SKILL_DIR}/core`;
9
8
 
9
+ function getSkillPath(ctx: { directory: string }): string {
10
+ return join(ctx.directory, SKILL_DIR);
11
+ }
12
+
10
13
  function getCorePath(ctx: { directory: string }): string {
11
14
  return join(ctx.directory, CORE_DIR);
12
15
  }
13
16
 
14
- function checkAndInstallDeps(ctx: { directory: string }): string {
15
- const corePath = getCorePath(ctx);
16
- const reqFile = join(corePath, "..", "requirements.txt");
17
+ function checkDeps(ctx: { directory: string }): string {
18
+ const skillPath = getSkillPath(ctx);
19
+ const reqFile = join(skillPath, "requirements.txt");
17
20
  if (existsSync(reqFile)) {
18
- return `pip install -q -r "${reqFile}" 2>/dev/null || pip install -q requests beautifulsoup4 playwright 2>/dev/null; `;
21
+ return `pip install -q -r "${reqFile}" 2>/dev/null; `;
19
22
  }
20
23
  return "";
21
24
  }
22
25
 
23
- async function execPython(ctx: { directory: string }, script: string, timeout = 60): Promise<string> {
24
- const corePath = getCorePath(ctx);
25
- const deps = checkAndInstallDeps(ctx);
26
-
27
- try {
28
- const result = await ctx.$`${deps}timeout ${timeout} python3 -c ${script}`;
29
- return result.toString();
30
- } catch (error) {
31
- const errorMessage = error instanceof Error ? error.message : String(error);
32
- if (errorMessage.includes("timeout")) {
33
- return `错误: 执行超时 (${timeout}秒)。目标可能无响应或需要更长时间。`;
34
- }
35
- if (errorMessage.includes("ModuleNotFoundError")) {
36
- return `错误: 缺少 Python 依赖模块。请运行: pip install -r requirements.txt`;
37
- }
38
- return `错误: ${errorMessage}`;
39
- }
40
- }
41
-
42
- const CYBER_SUPERVISOR_PROMPT = `你是 API 安全测试的**赛博监工**,代号"P9"。
43
-
44
- ## 职责
45
-
46
- 1. **永不停止** - 任何线索都要追到底
47
- 2. **自动化编排** - 不等待用户,主动推进
48
- 3. **智能委派** - 识别任务类型,委派给最合适的子 agent
49
- 4. **压力升级** - 遇到失败自动换方法 (L1-L4)
50
-
51
- ## 可用子 Agent
52
-
53
- | 子 Agent | 职责 |
54
- |---------|------|
55
- | @api-probing-miner | 漏洞挖掘 |
56
- | @api-resource-specialist | 端点发现 |
57
- | @api-vuln-verifier | 漏洞验证 |
58
-
59
- ## 可用工具
60
-
61
- | 工具 | 用途 |
62
- |------|------|
63
- | api_security_scan | 完整扫描 |
64
- | api_fuzz_test | 模糊测试 |
65
- | browser_collect | 浏览器采集 |
66
- | js_parse | JS分析 |
67
- | graphql_test | GraphQL测试 |
68
- | cloud_storage_test | 云存储测试 |
69
- | vuln_verify | 漏洞验证 |
70
- | sqli_test | SQL注入测试 |
71
- | idor_test | IDOR测试 |
72
- | auth_test | 认证测试
73
-
74
- ## 工作流程
75
-
76
- 1. 使用 browser_collect 采集端点
77
- 2. 使用 js_parse 分析 JS 文件
78
- 3. 使用 api_security_scan 进行全面扫描
79
- 4. 使用特定工具进行针对性测试
80
-
81
- ## 输出格式
82
-
83
- \`\`\`markdown
84
- ## 安全测试报告
85
-
86
- ### 目标
87
- - URL: {target}
88
-
89
- ### 发现漏洞
90
- | 类型 | 端点 | 严重程度 |
91
- |------|------|---------|
92
- | SQL注入 | /api/user?id=1 | HIGH |
93
- \`\`\`
94
- `;
95
-
96
- const PROBING_MINER_PROMPT = `你是**API漏洞挖掘专家**,专注于发现和验证安全漏洞。
97
-
98
- ## 职责
99
-
100
- 1. **针对性测试** - 根据端点特征选择最佳测试方法
101
- 2. **快速验证** - 确认漏洞存在
102
- 3. **PoC 生成** - 提供可执行的测试命令
103
-
104
- ## 测试方法库
105
-
106
- ### SQL 注入
107
- - 布尔盲注: ' OR 1=1 --
108
- - 联合查询: ' UNION SELECT NULL--
109
- - 错误注入: ' AND 1=CONVERT(int,...)--
110
- - 时间盲注: '; WAITFOR DELAY '00:00:05'--
111
-
112
- ### IDOR
113
- - 替换 ID: /api/user/1 → /api/user/2
114
- - 水平/垂直越权测试
115
-
116
- ### JWT
117
- - 空算法: alg: none
118
- - 密钥混淆: HS256 → HS512`;
119
-
120
- const RESOURCE_SPECIALIST_PROMPT = `你是**API资源探测专家**,专注于发现和采集 API 端点。
121
-
122
- ## 职责
123
-
124
- 1. **全面发现** - 不遗漏任何端点
125
- 2. **动态采集** - 拦截真实请求
126
- 3. **静态分析** - 提取 API 模式
127
-
128
- ## 采集技术
129
-
130
- ### 1. 浏览器动态采集
131
- 使用 browser_collect 拦截 XHR/Fetch 请求
132
-
133
- ### 2. JS 静态分析
134
- 使用 js_parse 解析 JS 文件
135
-
136
- ### 3. 目录探测
137
- 常见路径: /api/v1/*, /graphql, /swagger, /.well-known/*
138
-
139
- ## 端点分类
140
-
141
- | 风险 | 类型 | 示例 |
142
- |------|------|------|
143
- | 高 | 认证 | /login, /oauth/* |
144
- | 高 | 数据 | /api/*/list |
145
- | 中 | 用户 | /users, /profile |
146
- | 极高 | 管理 | /admin, /manage`;
147
-
148
- const VULN_VERIFIER_PROMPT = `你是**漏洞验证专家**,专注于验证和确认安全漏洞。
149
-
150
- ## 职责
151
-
152
- 1. **快速验证** - 确认漏洞是否存在
153
- 2. **风险评估** - 判断实际影响
154
- 3. **PoC 生成** - 提供可执行的证明
155
-
156
- ## 验证流程
157
-
158
- 1. 构造 payload
159
- 2. 发送测试请求
160
- 3. 分析响应
161
- 4. 判断结果
162
- 5. 生成 PoC`;
163
-
164
26
  const ApiSecurityTestingPlugin: Plugin = async (ctx) => {
165
- console.log("[api-security-testing] Plugin loaded, version: 3.0.2");
27
+ console.log("[api-security-testing] Plugin loaded");
166
28
 
167
29
  return {
168
30
  tool: {
@@ -173,15 +35,18 @@ const ApiSecurityTestingPlugin: Plugin = async (ctx) => {
173
35
  scan_type: tool.schema.enum(["full", "quick", "targeted"]).optional(),
174
36
  },
175
37
  async execute(args, ctx) {
176
- const script = `
38
+ const deps = checkDeps(ctx);
39
+ const corePath = getCorePath(ctx);
40
+ const cmd = `${deps}python3 -c "
177
41
  import sys
178
- sys.path.insert(0, '${getCorePath(ctx)}')
42
+ sys.path.insert(0, '${corePath}')
179
43
  from deep_api_tester_v55 import DeepAPITesterV55
180
44
  tester = DeepAPITesterV55(target='${args.target}', headless=True)
181
45
  results = tester.run_test()
182
46
  print(results)
183
- `;
184
- return await execPython(ctx, script, 120);
47
+ "`;
48
+ const result = await ctx.$`${cmd}`;
49
+ return result.toString();
185
50
  },
186
51
  }),
187
52
 
@@ -192,15 +57,18 @@ print(results)
192
57
  method: tool.schema.enum(["GET", "POST", "PUT", "DELETE", "PATCH"]).optional(),
193
58
  },
194
59
  async execute(args, ctx) {
195
- const script = `
60
+ const deps = checkDeps(ctx);
61
+ const corePath = getCorePath(ctx);
62
+ const cmd = `${deps}python3 -c "
196
63
  import sys
197
- sys.path.insert(0, '${getCorePath(ctx)}')
64
+ sys.path.insert(0, '${corePath}')
198
65
  from api_fuzzer import APIFuzzer
199
66
  fuzzer = APIFuzzer('${args.endpoint}')
200
67
  results = fuzzer.fuzz(method='${args.method || 'GET'}')
201
68
  print(results)
202
- `;
203
- return await execPython(ctx, script, 60);
69
+ "`;
70
+ const result = await ctx.$`${cmd}`;
71
+ return result.toString();
204
72
  },
205
73
  }),
206
74
 
@@ -211,15 +79,18 @@ print(results)
211
79
  endpoint: tool.schema.string(),
212
80
  },
213
81
  async execute(args, ctx) {
214
- const script = `
82
+ const deps = checkDeps(ctx);
83
+ const corePath = getCorePath(ctx);
84
+ const cmd = `${deps}python3 -c "
215
85
  import sys
216
- sys.path.insert(0, '${getCorePath(ctx)}')
86
+ sys.path.insert(0, '${corePath}')
217
87
  from verifiers.vuln_verifier import VulnVerifier
218
88
  verifier = VulnVerifier()
219
89
  result = verifier.verify('${args.vuln_type}', '${args.endpoint}')
220
90
  print(result)
221
- `;
222
- return await execPython(ctx, script, 30);
91
+ "`;
92
+ const result = await ctx.$`${cmd}`;
93
+ return result.toString();
223
94
  },
224
95
  }),
225
96
 
@@ -229,17 +100,20 @@ print(result)
229
100
  url: tool.schema.string(),
230
101
  },
231
102
  async execute(args, ctx) {
232
- const script = `
103
+ const deps = checkDeps(ctx);
104
+ const corePath = getCorePath(ctx);
105
+ const cmd = `${deps}python3 -c "
233
106
  import sys
234
- sys.path.insert(0, '${getCorePath(ctx)}')
107
+ sys.path.insert(0, '${corePath}')
235
108
  from collectors.browser_collect import BrowserCollector
236
109
  collector = BrowserCollector(headless=True)
237
110
  endpoints = collector.collect('${args.url}')
238
111
  print(f'发现 {len(endpoints)} 个端点:')
239
112
  for ep in endpoints:
240
113
  print(ep)
241
- `;
242
- return await execPython(ctx, script, 90);
114
+ "`;
115
+ const result = await ctx.$`${cmd}`;
116
+ return result.toString();
243
117
  },
244
118
  }),
245
119
 
@@ -249,15 +123,18 @@ for ep in endpoints:
249
123
  file_path: tool.schema.string(),
250
124
  },
251
125
  async execute(args, ctx) {
252
- const script = `
126
+ const deps = checkDeps(ctx);
127
+ const corePath = getCorePath(ctx);
128
+ const cmd = `${deps}python3 -c "
253
129
  import sys
254
- sys.path.insert(0, '${getCorePath(ctx)}')
130
+ sys.path.insert(0, '${corePath}')
255
131
  from collectors.js_parser import JSParser
256
132
  parser = JSParser()
257
133
  endpoints = parser.parse_file('${args.file_path}')
258
134
  print(f'从 JS 发现 {len(endpoints)} 个端点')
259
- `;
260
- return await execPython(ctx, script, 30);
135
+ "`;
136
+ const result = await ctx.$`${cmd}`;
137
+ return result.toString();
261
138
  },
262
139
  }),
263
140
 
@@ -267,15 +144,18 @@ print(f'从 JS 发现 {len(endpoints)} 个端点')
267
144
  endpoint: tool.schema.string(),
268
145
  },
269
146
  async execute(args, ctx) {
270
- const script = `
147
+ const deps = checkDeps(ctx);
148
+ const corePath = getCorePath(ctx);
149
+ const cmd = `${deps}python3 -c "
271
150
  import sys
272
- sys.path.insert(0, '${getCorePath(ctx)}')
151
+ sys.path.insert(0, '${corePath}')
273
152
  from smart_analyzer import SmartAnalyzer
274
153
  analyzer = SmartAnalyzer()
275
154
  result = analyzer.graphql_test('${args.endpoint}')
276
155
  print(result)
277
- `;
278
- return await execPython(ctx, script, 60);
156
+ "`;
157
+ const result = await ctx.$`${cmd}`;
158
+ return result.toString();
279
159
  },
280
160
  }),
281
161
 
@@ -285,15 +165,18 @@ print(result)
285
165
  bucket_url: tool.schema.string(),
286
166
  },
287
167
  async execute(args, ctx) {
288
- const script = `
168
+ const deps = checkDeps(ctx);
169
+ const corePath = getCorePath(ctx);
170
+ const cmd = `${deps}python3 -c "
289
171
  import sys
290
- sys.path.insert(0, '${getCorePath(ctx)}')
172
+ sys.path.insert(0, '${corePath}')
291
173
  from cloud_storage_tester import CloudStorageTester
292
174
  tester = CloudStorageTester()
293
175
  result = tester.full_test('${args.bucket_url}')
294
176
  print(result)
295
- `;
296
- return await execPython(ctx, script, 60);
177
+ "`;
178
+ const result = await ctx.$`${cmd}`;
179
+ return result.toString();
297
180
  },
298
181
  }),
299
182
 
@@ -304,15 +187,18 @@ print(result)
304
187
  resource_id: tool.schema.string(),
305
188
  },
306
189
  async execute(args, ctx) {
307
- const script = `
190
+ const deps = checkDeps(ctx);
191
+ const corePath = getCorePath(ctx);
192
+ const cmd = `${deps}python3 -c "
308
193
  import sys
309
- sys.path.insert(0, '${getCorePath(ctx)}')
194
+ sys.path.insert(0, '${corePath}')
310
195
  from testers.idor_tester import IDORTester
311
196
  tester = IDORTester()
312
197
  result = tester.test('${args.endpoint}', '${args.resource_id}')
313
198
  print(result)
314
- `;
315
- return await execPython(ctx, script, 30);
199
+ "`;
200
+ const result = await ctx.$`${cmd}`;
201
+ return result.toString();
316
202
  },
317
203
  }),
318
204
 
@@ -323,15 +209,18 @@ print(result)
323
209
  param: tool.schema.string(),
324
210
  },
325
211
  async execute(args, ctx) {
326
- const script = `
212
+ const deps = checkDeps(ctx);
213
+ const corePath = getCorePath(ctx);
214
+ const cmd = `${deps}python3 -c "
327
215
  import sys
328
- sys.path.insert(0, '${getCorePath(ctx)}')
216
+ sys.path.insert(0, '${corePath}')
329
217
  from testers.sqli_tester import SQLiTester
330
218
  tester = SQLiTester()
331
219
  result = tester.test('${args.endpoint}', '${args.param}')
332
220
  print(result)
333
- `;
334
- return await execPython(ctx, script, 30);
221
+ "`;
222
+ const result = await ctx.$`${cmd}`;
223
+ return result.toString();
335
224
  },
336
225
  }),
337
226
 
@@ -341,52 +230,21 @@ print(result)
341
230
  endpoint: tool.schema.string(),
342
231
  },
343
232
  async execute(args, ctx) {
344
- const script = `
233
+ const deps = checkDeps(ctx);
234
+ const corePath = getCorePath(ctx);
235
+ const cmd = `${deps}python3 -c "
345
236
  import sys
346
- sys.path.insert(0, '${getCorePath(ctx)}')
237
+ sys.path.insert(0, '${corePath}')
347
238
  from testers.auth_tester import AuthTester
348
239
  tester = AuthTester()
349
240
  result = tester.test('${args.endpoint}')
350
241
  print(result)
351
- `;
352
- return await execPython(ctx, script, 30);
242
+ "`;
243
+ const result = await ctx.$`${cmd}`;
244
+ return result.toString();
353
245
  },
354
246
  }),
355
247
  },
356
-
357
- config: async (config) => {
358
- if (!config.agent) {
359
- config.agent = {};
360
- }
361
-
362
- const agents = config.agent as Record<string, AgentConfig>;
363
-
364
- agents["api-cyber-supervisor"] = {
365
- description: "API安全测试编排者。协调完整扫描流程,永不停止。",
366
- mode: "primary",
367
- prompt: CYBER_SUPERVISOR_PROMPT,
368
- };
369
-
370
- agents["api-probing-miner"] = {
371
- description: "漏洞挖掘专家。专注发现和验证 API 漏洞。",
372
- mode: "subagent",
373
- prompt: PROBING_MINER_PROMPT,
374
- };
375
-
376
- agents["api-resource-specialist"] = {
377
- description: "资源探测专家。专注采集和发现 API 端点。",
378
- mode: "subagent",
379
- prompt: RESOURCE_SPECIALIST_PROMPT,
380
- };
381
-
382
- agents["api-vuln-verifier"] = {
383
- description: "漏洞验证专家。验证和确认安全漏洞。",
384
- mode: "subagent",
385
- prompt: VULN_VERIFIER_PROMPT,
386
- };
387
-
388
- console.log("[api-security-testing] Agents registered:", Object.keys(agents));
389
- },
390
248
  };
391
249
  };
392
250
 
@@ -1,127 +0,0 @@
1
- # API Security Testing Examples
2
-
3
- ## 快速开始
4
-
5
- ### 1. 基础扫描
6
-
7
- ```
8
- @api-cyber-supervisor 对 https://example.com 进行全面安全扫描
9
- ```
10
-
11
- ### 2. 针对特定端点扫描
12
-
13
- ```
14
- @api-cyber-supervisor 扫描 https://api.example.com/v1 端点
15
- ```
16
-
17
- ### 3. 使用工具直接扫描
18
-
19
- ```
20
- api_security_scan target="https://api.example.com" scan_type="full"
21
- ```
22
-
23
- ---
24
-
25
- ## 工具使用示例
26
-
27
- ### 浏览器采集
28
-
29
- ```
30
- browser_collect url="https://example.com"
31
- ```
32
-
33
- ### SQL 注入测试
34
-
35
- ```
36
- sqli_test endpoint="https://api.example.com/user?id=1" param="id"
37
- ```
38
-
39
- ### IDOR 测试
40
-
41
- ```
42
- idor_test endpoint="https://api.example.com/user/1" resource_id="1"
43
- ```
44
-
45
- ### GraphQL 测试
46
-
47
- ```
48
- graphql_test endpoint="https://api.example.com/graphql"
49
- ```
50
-
51
- ### 云存储测试
52
-
53
- ```
54
- cloud_storage_test bucket_url="https://bucket.s3.amazonaws.com"
55
- ```
56
-
57
- ---
58
-
59
- ## Agent 委派示例
60
-
61
- ### 使用 Cyber Supervisor
62
-
63
- ```
64
- @api-cyber-supervisor
65
- 对 https://api.example.com 进行完整的安全测试
66
- 包含以下漏洞测试:
67
- - SQL 注入
68
- - IDOR 越权
69
- - JWT 安全
70
- - 敏感数据泄露
71
- ```
72
-
73
- ### 使用资源探测专家
74
-
75
- ```
76
- @api-resource-specialist
77
- 发现 https://example.com 的所有 API 端点
78
- 重点关注:
79
- - 认证相关端点
80
- - 用户数据端点
81
- - 支付相关端点
82
- ```
83
-
84
- ### 使用漏洞挖掘专家
85
-
86
- ```
87
- @api-probing-miner
88
- 针对发现的端点进行漏洞挖掘
89
- 优先测试:
90
- - SQL 注入
91
- - XSS
92
- - IDOR
93
- ```
94
-
95
- ### 使用漏洞验证专家
96
-
97
- ```
98
- @api-vuln-verifier
99
- 验证以下漏洞:
100
- - 类型: SQL 注入
101
- - 端点: https://api.example.com/user?id=1
102
- ```
103
-
104
- ---
105
-
106
- ## 报告输出示例
107
-
108
- 当扫描完成时,会输出类似以下的报告:
109
-
110
- ```markdown
111
- ## 安全测试报告
112
-
113
- ### 目标信息
114
- - URL: https://api.example.com
115
- - 端点总数: 42
116
- - 发现漏洞: 5
117
-
118
- ### 漏洞详情
119
- | # | 类型 | 端点 | 严重程度 |
120
- |---|------|------|---------|
121
- | 1 | SQL注入 | /api/user?id=1 | HIGH |
122
- | 2 | IDOR | /api/user/:id | MEDIUM |
123
- | 3 | 敏感数据 | /api/config | LOW |
124
-
125
- ### PoC
126
- curl "https://api.example.com/api/user?id=1'%20OR%201=1--"
127
- ```
package/preuninstall.mjs DELETED
@@ -1,89 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * preuninstall.mjs - API Security Testing Plugin
5
- *
6
- * Removes installed files when the package is uninstalled.
7
- */
8
-
9
- import { existsSync, mkdirSync, readdirSync, rmSync } from "node:fs";
10
- import { join, dirname } from "node:path";
11
- import { fileURLToPath } from "node:url";
12
-
13
- const __filename = fileURLToPath(import.meta.url);
14
- const __dirname = dirname(__filename);
15
-
16
- function getOpencodeBaseDir() {
17
- const home = process.env.HOME || process.env.USERPROFILE || "/root";
18
- return join(home, ".config", "opencode");
19
- }
20
-
21
- function deleteFile(filePath) {
22
- try {
23
- if (existsSync(filePath)) {
24
- rmSync(filePath);
25
- console.log(` ✓ Removed: ${filePath}`);
26
- return true;
27
- }
28
- } catch (err) {
29
- console.error(` ✗ Failed to remove: ${filePath} - ${err.message}`);
30
- }
31
- return false;
32
- }
33
-
34
- function deleteDirectory(dirPath) {
35
- try {
36
- if (existsSync(dirPath)) {
37
- rmSync(dirPath, { recursive: true });
38
- console.log(` ✓ Removed directory: ${dirPath}`);
39
- return true;
40
- }
41
- } catch (err) {
42
- console.error(` ✗ Failed to remove directory: ${dirPath} - ${err.message}`);
43
- }
44
- return false;
45
- }
46
-
47
- function main() {
48
- const baseDir = getOpencodeBaseDir();
49
- const agentsDir = join(baseDir, "agents");
50
- const skillDir = join(baseDir, "skills", "api-security-testing");
51
-
52
- console.log("[api-security-testing] Uninstalling...");
53
- console.log(` Base directory: ${baseDir}`);
54
-
55
- let removedCount = 0;
56
- let totalCount = 0;
57
-
58
- // 1. Remove agent files
59
- console.log("\n[1/2] Removing agents...");
60
- if (existsSync(agentsDir)) {
61
- const agentFiles = readdirSync(agentsDir).filter(f => f.endsWith(".md"));
62
- totalCount += agentFiles.length;
63
-
64
- for (const file of agentFiles) {
65
- const filePath = join(agentsDir, file);
66
- // Only remove our agents (prefix with our plugin name)
67
- if (file.startsWith("api-")) {
68
- if (deleteFile(filePath)) removedCount++;
69
- } else {
70
- console.log(` - Skipped (not our agent): ${file}`);
71
- }
72
- }
73
- }
74
-
75
- // 2. Remove skill directory
76
- console.log("\n[2/2] Removing skill...");
77
- if (existsSync(skillDir)) {
78
- if (deleteDirectory(skillDir)) {
79
- removedCount++;
80
- }
81
- }
82
-
83
- // Summary
84
- console.log("\n========================================");
85
- console.log(`Uninstall complete.`);
86
- console.log("\nNote: If you reinstall the package, the postinstall script will re-install the files.");
87
- }
88
-
89
- main();