opencode-api-security-testing 3.0.3 → 3.0.4

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.4",
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
@@ -7,38 +7,23 @@ import { existsSync } from "fs";
7
7
  const SKILL_DIR = "skills/api-security-testing";
8
8
  const CORE_DIR = `${SKILL_DIR}/core`;
9
9
 
10
+ function getSkillPath(ctx: { directory: string }): string {
11
+ return join(ctx.directory, SKILL_DIR);
12
+ }
13
+
10
14
  function getCorePath(ctx: { directory: string }): string {
11
15
  return join(ctx.directory, CORE_DIR);
12
16
  }
13
17
 
14
- function checkAndInstallDeps(ctx: { directory: string }): string {
15
- const corePath = getCorePath(ctx);
16
- const reqFile = join(corePath, "..", "requirements.txt");
18
+ function checkDeps(ctx: { directory: string }): string {
19
+ const skillPath = getSkillPath(ctx);
20
+ const reqFile = join(skillPath, "requirements.txt");
17
21
  if (existsSync(reqFile)) {
18
- return `pip install -q -r "${reqFile}" 2>/dev/null || pip install -q requests beautifulsoup4 playwright 2>/dev/null; `;
22
+ return `pip install -q -r "${reqFile}" 2>/dev/null; `;
19
23
  }
20
24
  return "";
21
25
  }
22
26
 
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
27
  const CYBER_SUPERVISOR_PROMPT = `你是 API 安全测试的**赛博监工**,代号"P9"。
43
28
 
44
29
  ## 职责
@@ -69,29 +54,7 @@ const CYBER_SUPERVISOR_PROMPT = `你是 API 安全测试的**赛博监工**,
69
54
  | vuln_verify | 漏洞验证 |
70
55
  | sqli_test | SQL注入测试 |
71
56
  | 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
- `;
57
+ | auth_test | 认证测试`;
95
58
 
96
59
  const PROBING_MINER_PROMPT = `你是**API漏洞挖掘专家**,专注于发现和验证安全漏洞。
97
60
 
@@ -134,16 +97,7 @@ const RESOURCE_SPECIALIST_PROMPT = `你是**API资源探测专家**,专注于
134
97
  使用 js_parse 解析 JS 文件
135
98
 
136
99
  ### 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`;
100
+ 常见路径: /api/v1/*, /graphql, /swagger, /.well-known/*`;
147
101
 
148
102
  const VULN_VERIFIER_PROMPT = `你是**漏洞验证专家**,专注于验证和确认安全漏洞。
149
103
 
@@ -151,18 +105,10 @@ const VULN_VERIFIER_PROMPT = `你是**漏洞验证专家**,专注于验证和
151
105
 
152
106
  1. **快速验证** - 确认漏洞是否存在
153
107
  2. **风险评估** - 判断实际影响
154
- 3. **PoC 生成** - 提供可执行的证明
155
-
156
- ## 验证流程
157
-
158
- 1. 构造 payload
159
- 2. 发送测试请求
160
- 3. 分析响应
161
- 4. 判断结果
162
- 5. 生成 PoC`;
108
+ 3. **PoC 生成** - 提供可执行的证明`;
163
109
 
164
110
  const ApiSecurityTestingPlugin: Plugin = async (ctx) => {
165
- console.log("[api-security-testing] Plugin loaded, version: 3.0.2");
111
+ console.log("[api-security-testing] Plugin loaded");
166
112
 
167
113
  return {
168
114
  tool: {
@@ -173,15 +119,18 @@ const ApiSecurityTestingPlugin: Plugin = async (ctx) => {
173
119
  scan_type: tool.schema.enum(["full", "quick", "targeted"]).optional(),
174
120
  },
175
121
  async execute(args, ctx) {
176
- const script = `
122
+ const deps = checkDeps(ctx);
123
+ const corePath = getCorePath(ctx);
124
+ const cmd = `${deps}python3 -c "
177
125
  import sys
178
- sys.path.insert(0, '${getCorePath(ctx)}')
126
+ sys.path.insert(0, '${corePath}')
179
127
  from deep_api_tester_v55 import DeepAPITesterV55
180
128
  tester = DeepAPITesterV55(target='${args.target}', headless=True)
181
129
  results = tester.run_test()
182
130
  print(results)
183
- `;
184
- return await execPython(ctx, script, 120);
131
+ "`;
132
+ const result = await ctx.$`${cmd}`;
133
+ return result.toString();
185
134
  },
186
135
  }),
187
136
 
@@ -192,15 +141,18 @@ print(results)
192
141
  method: tool.schema.enum(["GET", "POST", "PUT", "DELETE", "PATCH"]).optional(),
193
142
  },
194
143
  async execute(args, ctx) {
195
- const script = `
144
+ const deps = checkDeps(ctx);
145
+ const corePath = getCorePath(ctx);
146
+ const cmd = `${deps}python3 -c "
196
147
  import sys
197
- sys.path.insert(0, '${getCorePath(ctx)}')
148
+ sys.path.insert(0, '${corePath}')
198
149
  from api_fuzzer import APIFuzzer
199
150
  fuzzer = APIFuzzer('${args.endpoint}')
200
151
  results = fuzzer.fuzz(method='${args.method || 'GET'}')
201
152
  print(results)
202
- `;
203
- return await execPython(ctx, script, 60);
153
+ "`;
154
+ const result = await ctx.$`${cmd}`;
155
+ return result.toString();
204
156
  },
205
157
  }),
206
158
 
@@ -211,15 +163,18 @@ print(results)
211
163
  endpoint: tool.schema.string(),
212
164
  },
213
165
  async execute(args, ctx) {
214
- const script = `
166
+ const deps = checkDeps(ctx);
167
+ const corePath = getCorePath(ctx);
168
+ const cmd = `${deps}python3 -c "
215
169
  import sys
216
- sys.path.insert(0, '${getCorePath(ctx)}')
170
+ sys.path.insert(0, '${corePath}')
217
171
  from verifiers.vuln_verifier import VulnVerifier
218
172
  verifier = VulnVerifier()
219
173
  result = verifier.verify('${args.vuln_type}', '${args.endpoint}')
220
174
  print(result)
221
- `;
222
- return await execPython(ctx, script, 30);
175
+ "`;
176
+ const result = await ctx.$`${cmd}`;
177
+ return result.toString();
223
178
  },
224
179
  }),
225
180
 
@@ -229,17 +184,20 @@ print(result)
229
184
  url: tool.schema.string(),
230
185
  },
231
186
  async execute(args, ctx) {
232
- const script = `
187
+ const deps = checkDeps(ctx);
188
+ const corePath = getCorePath(ctx);
189
+ const cmd = `${deps}python3 -c "
233
190
  import sys
234
- sys.path.insert(0, '${getCorePath(ctx)}')
191
+ sys.path.insert(0, '${corePath}')
235
192
  from collectors.browser_collect import BrowserCollector
236
193
  collector = BrowserCollector(headless=True)
237
194
  endpoints = collector.collect('${args.url}')
238
195
  print(f'发现 {len(endpoints)} 个端点:')
239
196
  for ep in endpoints:
240
197
  print(ep)
241
- `;
242
- return await execPython(ctx, script, 90);
198
+ "`;
199
+ const result = await ctx.$`${cmd}`;
200
+ return result.toString();
243
201
  },
244
202
  }),
245
203
 
@@ -249,15 +207,18 @@ for ep in endpoints:
249
207
  file_path: tool.schema.string(),
250
208
  },
251
209
  async execute(args, ctx) {
252
- const script = `
210
+ const deps = checkDeps(ctx);
211
+ const corePath = getCorePath(ctx);
212
+ const cmd = `${deps}python3 -c "
253
213
  import sys
254
- sys.path.insert(0, '${getCorePath(ctx)}')
214
+ sys.path.insert(0, '${corePath}')
255
215
  from collectors.js_parser import JSParser
256
216
  parser = JSParser()
257
217
  endpoints = parser.parse_file('${args.file_path}')
258
218
  print(f'从 JS 发现 {len(endpoints)} 个端点')
259
- `;
260
- return await execPython(ctx, script, 30);
219
+ "`;
220
+ const result = await ctx.$`${cmd}`;
221
+ return result.toString();
261
222
  },
262
223
  }),
263
224
 
@@ -267,15 +228,18 @@ print(f'从 JS 发现 {len(endpoints)} 个端点')
267
228
  endpoint: tool.schema.string(),
268
229
  },
269
230
  async execute(args, ctx) {
270
- const script = `
231
+ const deps = checkDeps(ctx);
232
+ const corePath = getCorePath(ctx);
233
+ const cmd = `${deps}python3 -c "
271
234
  import sys
272
- sys.path.insert(0, '${getCorePath(ctx)}')
235
+ sys.path.insert(0, '${corePath}')
273
236
  from smart_analyzer import SmartAnalyzer
274
237
  analyzer = SmartAnalyzer()
275
238
  result = analyzer.graphql_test('${args.endpoint}')
276
239
  print(result)
277
- `;
278
- return await execPython(ctx, script, 60);
240
+ "`;
241
+ const result = await ctx.$`${cmd}`;
242
+ return result.toString();
279
243
  },
280
244
  }),
281
245
 
@@ -285,15 +249,18 @@ print(result)
285
249
  bucket_url: tool.schema.string(),
286
250
  },
287
251
  async execute(args, ctx) {
288
- const script = `
252
+ const deps = checkDeps(ctx);
253
+ const corePath = getCorePath(ctx);
254
+ const cmd = `${deps}python3 -c "
289
255
  import sys
290
- sys.path.insert(0, '${getCorePath(ctx)}')
256
+ sys.path.insert(0, '${corePath}')
291
257
  from cloud_storage_tester import CloudStorageTester
292
258
  tester = CloudStorageTester()
293
259
  result = tester.full_test('${args.bucket_url}')
294
260
  print(result)
295
- `;
296
- return await execPython(ctx, script, 60);
261
+ "`;
262
+ const result = await ctx.$`${cmd}`;
263
+ return result.toString();
297
264
  },
298
265
  }),
299
266
 
@@ -304,15 +271,18 @@ print(result)
304
271
  resource_id: tool.schema.string(),
305
272
  },
306
273
  async execute(args, ctx) {
307
- const script = `
274
+ const deps = checkDeps(ctx);
275
+ const corePath = getCorePath(ctx);
276
+ const cmd = `${deps}python3 -c "
308
277
  import sys
309
- sys.path.insert(0, '${getCorePath(ctx)}')
278
+ sys.path.insert(0, '${corePath}')
310
279
  from testers.idor_tester import IDORTester
311
280
  tester = IDORTester()
312
281
  result = tester.test('${args.endpoint}', '${args.resource_id}')
313
282
  print(result)
314
- `;
315
- return await execPython(ctx, script, 30);
283
+ "`;
284
+ const result = await ctx.$`${cmd}`;
285
+ return result.toString();
316
286
  },
317
287
  }),
318
288
 
@@ -323,15 +293,18 @@ print(result)
323
293
  param: tool.schema.string(),
324
294
  },
325
295
  async execute(args, ctx) {
326
- const script = `
296
+ const deps = checkDeps(ctx);
297
+ const corePath = getCorePath(ctx);
298
+ const cmd = `${deps}python3 -c "
327
299
  import sys
328
- sys.path.insert(0, '${getCorePath(ctx)}')
300
+ sys.path.insert(0, '${corePath}')
329
301
  from testers.sqli_tester import SQLiTester
330
302
  tester = SQLiTester()
331
303
  result = tester.test('${args.endpoint}', '${args.param}')
332
304
  print(result)
333
- `;
334
- return await execPython(ctx, script, 30);
305
+ "`;
306
+ const result = await ctx.$`${cmd}`;
307
+ return result.toString();
335
308
  },
336
309
  }),
337
310
 
@@ -341,15 +314,18 @@ print(result)
341
314
  endpoint: tool.schema.string(),
342
315
  },
343
316
  async execute(args, ctx) {
344
- const script = `
317
+ const deps = checkDeps(ctx);
318
+ const corePath = getCorePath(ctx);
319
+ const cmd = `${deps}python3 -c "
345
320
  import sys
346
- sys.path.insert(0, '${getCorePath(ctx)}')
321
+ sys.path.insert(0, '${corePath}')
347
322
  from testers.auth_tester import AuthTester
348
323
  tester = AuthTester()
349
324
  result = tester.test('${args.endpoint}')
350
325
  print(result)
351
- `;
352
- return await execPython(ctx, script, 30);
326
+ "`;
327
+ const result = await ctx.$`${cmd}`;
328
+ return result.toString();
353
329
  },
354
330
  }),
355
331
  },
@@ -385,7 +361,7 @@ print(result)
385
361
  prompt: VULN_VERIFIER_PROMPT,
386
362
  };
387
363
 
388
- console.log("[api-security-testing] Agents registered:", Object.keys(agents));
364
+ console.log("[api-security-testing] Tools registered");
389
365
  },
390
366
  };
391
367
  };
@@ -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();