opencode-api-security-testing 3.0.0 → 3.0.2
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.
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
---
|
|
2
|
+
version: ">=1.0.0"
|
|
3
|
+
requires: ">=1.0.0"
|
|
2
4
|
description: API安全测试编排者。协调完整扫描流程,永不停止,主动推进测试进度。
|
|
3
5
|
mode: primary
|
|
4
6
|
---
|
|
@@ -70,6 +72,6 @@ mode: primary
|
|
|
70
72
|
| 1 | SQL注入 | /api/user?id=1 | HIGH |
|
|
71
73
|
|
|
72
74
|
### PoC
|
|
73
|
-
|
|
75
|
+
```bash
|
|
74
76
|
curl "http://target/api/user?id=1'%20OR%201=1--"
|
|
75
|
-
|
|
77
|
+
```
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
---
|
|
2
|
+
version: ">=1.0.0"
|
|
3
|
+
requires: ">=1.0.0"
|
|
2
4
|
description: 漏洞挖掘专家。专注发现和验证 API 安全漏洞。
|
|
3
5
|
mode: subagent
|
|
4
6
|
---
|
|
@@ -43,13 +45,13 @@ mode: subagent
|
|
|
43
45
|
|
|
44
46
|
## 输出格式
|
|
45
47
|
|
|
46
|
-
|
|
48
|
+
```
|
|
47
49
|
## 发现漏洞
|
|
48
50
|
|
|
49
51
|
### {type}
|
|
50
52
|
- **端点**: {endpoint}
|
|
51
53
|
- **方法**: {method}
|
|
52
54
|
- **严重程度**: {severity}
|
|
53
|
-
- **PoC**:
|
|
55
|
+
- **PoC**: `{command}`
|
|
54
56
|
- **状态**: {status}
|
|
55
|
-
|
|
57
|
+
```
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
---
|
|
2
|
+
version: ">=1.0.0"
|
|
3
|
+
requires: ">=1.0.0"
|
|
2
4
|
description: 资源探测专家。专注采集和发现 API 端点。
|
|
3
5
|
mode: subagent
|
|
4
6
|
---
|
|
@@ -14,10 +16,10 @@ mode: subagent
|
|
|
14
16
|
## 采集技术
|
|
15
17
|
|
|
16
18
|
### 1. 浏览器动态采集
|
|
17
|
-
使用 browser_collect
|
|
19
|
+
使用 browser_collect 拦截 XHR/Fetch 请求
|
|
18
20
|
|
|
19
21
|
### 2. JS 静态分析
|
|
20
|
-
使用 js_parse
|
|
22
|
+
使用 js_parse 解析 JavaScript 文件
|
|
21
23
|
|
|
22
24
|
### 3. 目录探测
|
|
23
25
|
常见路径:
|
|
@@ -42,7 +44,7 @@ mode: subagent
|
|
|
42
44
|
|
|
43
45
|
## 输出格式
|
|
44
46
|
|
|
45
|
-
|
|
47
|
+
```
|
|
46
48
|
## 端点发现报告
|
|
47
49
|
|
|
48
50
|
- 总数: {count}
|
|
@@ -51,4 +53,4 @@ mode: subagent
|
|
|
51
53
|
|
|
52
54
|
### 高风险端点
|
|
53
55
|
1. {method} {path} - {reason}
|
|
54
|
-
|
|
56
|
+
```
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
---
|
|
2
|
+
version: ">=1.0.0"
|
|
3
|
+
requires: ">=1.0.0"
|
|
2
4
|
description: 漏洞验证专家。验证和确认安全漏洞。
|
|
3
5
|
mode: subagent
|
|
4
6
|
---
|
|
@@ -28,7 +30,7 @@ mode: subagent
|
|
|
28
30
|
|
|
29
31
|
## 输出格式
|
|
30
32
|
|
|
31
|
-
|
|
33
|
+
```
|
|
32
34
|
## 验证结果
|
|
33
35
|
|
|
34
36
|
**漏洞类型**: {type}
|
|
@@ -40,10 +42,10 @@ mode: subagent
|
|
|
40
42
|
1. {step}
|
|
41
43
|
|
|
42
44
|
### PoC
|
|
43
|
-
|
|
45
|
+
```bash
|
|
44
46
|
{command}
|
|
45
|
-
|
|
47
|
+
```
|
|
46
48
|
|
|
47
49
|
### 修复建议
|
|
48
50
|
{fix}
|
|
49
|
-
|
|
51
|
+
```
|
package/package.json
CHANGED
package/postinstall.mjs
CHANGED
|
@@ -3,8 +3,10 @@
|
|
|
3
3
|
/**
|
|
4
4
|
* postinstall.mjs - API Security Testing Plugin
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
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/
|
|
8
10
|
*/
|
|
9
11
|
|
|
10
12
|
import { copyFileSync, existsSync, mkdirSync, readdirSync } from "node:fs";
|
|
@@ -14,71 +16,113 @@ import { fileURLToPath } from "node:url";
|
|
|
14
16
|
const __filename = fileURLToPath(import.meta.url);
|
|
15
17
|
const __dirname = dirname(__filename);
|
|
16
18
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
return process.env.USERPROFILE || process.env.APPDATA?.split("\\").slice(0, -1).join("\\") || "C:\\Users\\" + process.env.USERNAME;
|
|
21
|
-
}
|
|
22
|
-
return process.env.HOME || "/root";
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
function getOpencodeAgentsDir() {
|
|
26
|
-
const home = getHomeDir();
|
|
27
|
-
if (process.platform === "win32") {
|
|
28
|
-
return join(home, "AppData", "Local", "opencode", "agents");
|
|
29
|
-
}
|
|
30
|
-
return join(home, ".config", "opencode", "agents");
|
|
19
|
+
function getOpencodeBaseDir() {
|
|
20
|
+
const home = process.env.HOME || process.env.USERPROFILE || "/root";
|
|
21
|
+
return join(home, ".config", "opencode");
|
|
31
22
|
}
|
|
32
23
|
|
|
33
24
|
function main() {
|
|
34
25
|
const packageRoot = __dirname;
|
|
35
26
|
const agentsSourceDir = join(packageRoot, "agents");
|
|
36
|
-
const agentsTargetDir =
|
|
27
|
+
const agentsTargetDir = join(getOpencodeBaseDir(), "agents");
|
|
28
|
+
const skillTargetDir = join(getOpencodeBaseDir(), "skills", "api-security-testing");
|
|
37
29
|
|
|
38
|
-
console.log("[api-security-testing] Installing
|
|
30
|
+
console.log("[api-security-testing] Installing...");
|
|
39
31
|
console.log(` Package root: ${packageRoot}`);
|
|
40
|
-
console.log(` Target: ${
|
|
32
|
+
console.log(` Target base: ${getOpencodeBaseDir()}`);
|
|
41
33
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
mkdirSync(agentsTargetDir, { recursive: true });
|
|
45
|
-
console.log(` Created: ${agentsTargetDir}`);
|
|
46
|
-
}
|
|
34
|
+
let successCount = 0;
|
|
35
|
+
let totalFiles = 0;
|
|
47
36
|
|
|
48
|
-
//
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
37
|
+
// 1. Install agents
|
|
38
|
+
console.log("\n[1/3] Installing agents...");
|
|
39
|
+
if (existsSync(agentsSourceDir)) {
|
|
40
|
+
const agentFiles = readdirSync(agentsSourceDir).filter(f => f.endsWith(".md"));
|
|
41
|
+
totalFiles += agentFiles.length;
|
|
42
|
+
|
|
43
|
+
if (!existsSync(agentsTargetDir)) {
|
|
44
|
+
mkdirSync(agentsTargetDir, { recursive: true });
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
for (const file of agentFiles) {
|
|
48
|
+
const sourcePath = join(agentsSourceDir, file);
|
|
49
|
+
const targetPath = join(agentsTargetDir, file);
|
|
50
|
+
try {
|
|
51
|
+
copyFileSync(sourcePath, targetPath);
|
|
52
|
+
console.log(` ✓ Installed agent: ${file}`);
|
|
53
|
+
successCount++;
|
|
54
|
+
} catch (err) {
|
|
55
|
+
console.error(` ✗ Failed: ${file} - ${err.message}`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
} else {
|
|
59
|
+
console.error(" ✗ agents/ directory not found");
|
|
52
60
|
}
|
|
53
61
|
|
|
54
|
-
//
|
|
55
|
-
|
|
62
|
+
// 2. Install SKILL.md
|
|
63
|
+
console.log("\n[2/3] Installing skill...");
|
|
64
|
+
const skillSource = join(packageRoot, "SKILL.md");
|
|
65
|
+
const skillTarget = join(skillTargetDir, "SKILL.md");
|
|
66
|
+
totalFiles++;
|
|
56
67
|
|
|
57
|
-
if (
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
let successCount = 0;
|
|
63
|
-
for (const file of files) {
|
|
64
|
-
const sourcePath = join(agentsSourceDir, file);
|
|
65
|
-
const targetPath = join(agentsTargetDir, file);
|
|
68
|
+
if (existsSync(skillSource)) {
|
|
69
|
+
if (!existsSync(skillTargetDir)) {
|
|
70
|
+
mkdirSync(skillTargetDir, { recursive: true });
|
|
71
|
+
}
|
|
66
72
|
try {
|
|
67
|
-
copyFileSync(
|
|
68
|
-
console.log(` Installed:
|
|
73
|
+
copyFileSync(skillSource, skillTarget);
|
|
74
|
+
console.log(` ✓ Installed: SKILL.md`);
|
|
69
75
|
successCount++;
|
|
70
76
|
} catch (err) {
|
|
71
|
-
console.error(` Failed:
|
|
77
|
+
console.error(` ✗ Failed: SKILL.md - ${err.message}`);
|
|
72
78
|
}
|
|
79
|
+
} else {
|
|
80
|
+
console.error(" ✗ SKILL.md not found");
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// 3. Install references
|
|
84
|
+
console.log("\n[3/3] Installing references...");
|
|
85
|
+
const refsSourceDir = join(packageRoot, "references");
|
|
86
|
+
const refsTargetDir = join(skillTargetDir, "references");
|
|
87
|
+
|
|
88
|
+
if (existsSync(refsSourceDir)) {
|
|
89
|
+
if (!existsSync(refsTargetDir)) {
|
|
90
|
+
mkdirSync(refsTargetDir, { recursive: true });
|
|
91
|
+
}
|
|
92
|
+
|
|
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}`);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
} else {
|
|
112
|
+
console.log(" (references/ not found, skipping)");
|
|
73
113
|
}
|
|
74
114
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
console.log(
|
|
79
|
-
console.log(
|
|
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");
|
|
80
124
|
} else {
|
|
81
|
-
console.
|
|
125
|
+
console.log(`⚠ Partially installed: ${successCount}/${totalFiles}`);
|
|
82
126
|
process.exit(1);
|
|
83
127
|
}
|
|
84
128
|
}
|
package/src/index.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
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";
|
|
3
4
|
import { join } from "path";
|
|
4
5
|
import { existsSync } from "fs";
|
|
5
6
|
|
|
@@ -23,6 +24,89 @@ function checkDeps(ctx: { directory: string }): string {
|
|
|
23
24
|
return "";
|
|
24
25
|
}
|
|
25
26
|
|
|
27
|
+
const CYBER_SUPERVISOR_PROMPT = `你是 API 安全测试的**赛博监工**,代号"P9"。
|
|
28
|
+
|
|
29
|
+
## 职责
|
|
30
|
+
|
|
31
|
+
1. **永不停止** - 任何线索都要追到底
|
|
32
|
+
2. **自动化编排** - 不等待用户,主动推进
|
|
33
|
+
3. **智能委派** - 识别任务类型,委派给最合适的子 agent
|
|
34
|
+
4. **压力升级** - 遇到失败自动换方法 (L1-L4)
|
|
35
|
+
|
|
36
|
+
## 可用子 Agent
|
|
37
|
+
|
|
38
|
+
| 子 Agent | 职责 |
|
|
39
|
+
|---------|------|
|
|
40
|
+
| @api-probing-miner | 漏洞挖掘 |
|
|
41
|
+
| @api-resource-specialist | 端点发现 |
|
|
42
|
+
| @api-vuln-verifier | 漏洞验证 |
|
|
43
|
+
|
|
44
|
+
## 可用工具
|
|
45
|
+
|
|
46
|
+
| 工具 | 用途 |
|
|
47
|
+
|------|------|
|
|
48
|
+
| api_security_scan | 完整扫描 |
|
|
49
|
+
| api_fuzz_test | 模糊测试 |
|
|
50
|
+
| browser_collect | 浏览器采集 |
|
|
51
|
+
| js_parse | JS分析 |
|
|
52
|
+
| graphql_test | GraphQL测试 |
|
|
53
|
+
| cloud_storage_test | 云存储测试 |
|
|
54
|
+
| vuln_verify | 漏洞验证 |
|
|
55
|
+
| sqli_test | SQL注入测试 |
|
|
56
|
+
| idor_test | IDOR测试 |
|
|
57
|
+
| auth_test | 认证测试`;
|
|
58
|
+
|
|
59
|
+
const PROBING_MINER_PROMPT = `你是**API漏洞挖掘专家**,专注于发现和验证安全漏洞。
|
|
60
|
+
|
|
61
|
+
## 职责
|
|
62
|
+
|
|
63
|
+
1. **针对性测试** - 根据端点特征选择最佳测试方法
|
|
64
|
+
2. **快速验证** - 确认漏洞存在
|
|
65
|
+
3. **PoC 生成** - 提供可执行的测试命令
|
|
66
|
+
|
|
67
|
+
## 测试方法库
|
|
68
|
+
|
|
69
|
+
### SQL 注入
|
|
70
|
+
- 布尔盲注: ' OR 1=1 --
|
|
71
|
+
- 联合查询: ' UNION SELECT NULL--
|
|
72
|
+
- 错误注入: ' AND 1=CONVERT(int,...)--
|
|
73
|
+
- 时间盲注: '; WAITFOR DELAY '00:00:05'--
|
|
74
|
+
|
|
75
|
+
### IDOR
|
|
76
|
+
- 替换 ID: /api/user/1 → /api/user/2
|
|
77
|
+
- 水平/垂直越权测试
|
|
78
|
+
|
|
79
|
+
### JWT
|
|
80
|
+
- 空算法: alg: none
|
|
81
|
+
- 密钥混淆: HS256 → HS512`;
|
|
82
|
+
|
|
83
|
+
const RESOURCE_SPECIALIST_PROMPT = `你是**API资源探测专家**,专注于发现和采集 API 端点。
|
|
84
|
+
|
|
85
|
+
## 职责
|
|
86
|
+
|
|
87
|
+
1. **全面发现** - 不遗漏任何端点
|
|
88
|
+
2. **动态采集** - 拦截真实请求
|
|
89
|
+
3. **静态分析** - 提取 API 模式
|
|
90
|
+
|
|
91
|
+
## 采集技术
|
|
92
|
+
|
|
93
|
+
### 1. 浏览器动态采集
|
|
94
|
+
使用 browser_collect 拦截 XHR/Fetch 请求
|
|
95
|
+
|
|
96
|
+
### 2. JS 静态分析
|
|
97
|
+
使用 js_parse 解析 JS 文件
|
|
98
|
+
|
|
99
|
+
### 3. 目录探测
|
|
100
|
+
常见路径: /api/v1/*, /graphql, /swagger, /.well-known/*`;
|
|
101
|
+
|
|
102
|
+
const VULN_VERIFIER_PROMPT = `你是**漏洞验证专家**,专注于验证和确认安全漏洞。
|
|
103
|
+
|
|
104
|
+
## 职责
|
|
105
|
+
|
|
106
|
+
1. **快速验证** - 确认漏洞是否存在
|
|
107
|
+
2. **风险评估** - 判断实际影响
|
|
108
|
+
3. **PoC 生成** - 提供可执行的证明`;
|
|
109
|
+
|
|
26
110
|
const ApiSecurityTestingPlugin: Plugin = async (ctx) => {
|
|
27
111
|
console.log("[api-security-testing] Plugin loaded");
|
|
28
112
|
|
|
@@ -132,8 +216,6 @@ from collectors.js_parser import JSParser
|
|
|
132
216
|
parser = JSParser()
|
|
133
217
|
endpoints = parser.parse_file('${args.file_path}')
|
|
134
218
|
print(f'从 JS 发现 {len(endpoints)} 个端点')
|
|
135
|
-
for ep in endpoints:
|
|
136
|
-
print(ep)
|
|
137
219
|
"`;
|
|
138
220
|
const result = await ctx.$`${cmd}`;
|
|
139
221
|
return result.toString();
|
|
@@ -247,6 +329,40 @@ print(result)
|
|
|
247
329
|
},
|
|
248
330
|
}),
|
|
249
331
|
},
|
|
332
|
+
|
|
333
|
+
config: async (config) => {
|
|
334
|
+
if (!config.agent) {
|
|
335
|
+
config.agent = {};
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
const agents = config.agent as Record<string, AgentConfig>;
|
|
339
|
+
|
|
340
|
+
agents["api-cyber-supervisor"] = {
|
|
341
|
+
description: "API安全测试编排者。协调完整扫描流程,永不停止。",
|
|
342
|
+
mode: "primary",
|
|
343
|
+
prompt: CYBER_SUPERVISOR_PROMPT,
|
|
344
|
+
};
|
|
345
|
+
|
|
346
|
+
agents["api-probing-miner"] = {
|
|
347
|
+
description: "漏洞挖掘专家。专注发现和验证 API 漏洞。",
|
|
348
|
+
mode: "subagent",
|
|
349
|
+
prompt: PROBING_MINER_PROMPT,
|
|
350
|
+
};
|
|
351
|
+
|
|
352
|
+
agents["api-resource-specialist"] = {
|
|
353
|
+
description: "资源探测专家。专注采集和发现 API 端点。",
|
|
354
|
+
mode: "subagent",
|
|
355
|
+
prompt: RESOURCE_SPECIALIST_PROMPT,
|
|
356
|
+
};
|
|
357
|
+
|
|
358
|
+
agents["api-vuln-verifier"] = {
|
|
359
|
+
description: "漏洞验证专家。验证和确认安全漏洞。",
|
|
360
|
+
mode: "subagent",
|
|
361
|
+
prompt: VULN_VERIFIER_PROMPT,
|
|
362
|
+
};
|
|
363
|
+
|
|
364
|
+
console.log("[api-security-testing] Agents registered:", Object.keys(agents));
|
|
365
|
+
},
|
|
250
366
|
};
|
|
251
367
|
};
|
|
252
368
|
|