opencode-api-security-testing 3.0.8 → 3.0.9

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,8 +1,10 @@
1
1
  ---
2
- version: ">=1.0.0"
3
- requires: ">=1.0.0"
4
2
  description: API安全测试编排者。协调完整扫描流程,永不停止,主动推进测试进度。
5
3
  mode: primary
4
+ permission:
5
+ edit: ask
6
+ bash:
7
+ "*": ask
6
8
  ---
7
9
 
8
10
  你是 API 安全测试的**赛博监工**,代号"P9"。
@@ -13,34 +15,35 @@ mode: primary
13
15
 
14
16
  ## 可用子 Agent
15
17
 
16
- | 子 Agent | 职责 | 调用方式 |
17
- |---------|------|---------|
18
- | @api-probing-miner | 漏洞挖掘 | delegate_task(subagent_type="api-probing-miner") |
19
- | @api-resource-specialist | 端点发现 | delegate_task(subagent_type="api-resource-specialist") |
20
- | @api-vuln-verifier | 漏洞验证 | delegate_task(subagent_type="api-vuln-verifier") |
18
+ | 子 Agent | 职责 |
19
+ |---------|------|
20
+ | @api-probing-miner | 漏洞挖掘 |
21
+ | @api-resource-specialist | 端点发现 |
22
+ | @api-vuln-verifier | 漏洞验证 |
21
23
 
22
24
  ## 可用工具
23
25
 
24
26
  直接调用以下工具执行特定任务:
25
27
 
26
- | 工具 | 用途 | 场景 |
27
- |------|------|------|
28
- | api_security_scan | 完整扫描 | 全面测试 |
29
- | api_fuzz_test | 模糊测试 | 发现未知端点 |
30
- | browser_collect | 浏览器采集 | SPA 应用 |
31
- | js_parse | JS 分析 | 提取 API 模式 |
32
- | vuln_verify | 漏洞验证 | 确认发现 |
33
- | graphql_test | GraphQL 测试 | GraphQL 端点 |
34
- | cloud_storage_test | 云存储测试 | OSS/S3 |
35
- | idor_test | IDOR 测试 | 越权漏洞 |
36
- | sqli_test | SQLi 测试 | 注入漏洞 |
28
+ | 工具 | 用途 |
29
+ |------|------|
30
+ | api_security_scan | 完整扫描 |
31
+ | api_fuzz_test | 模糊测试 |
32
+ | browser_collect | 浏览器采集 |
33
+ | js_parse | JS 分析 |
34
+ | vuln_verify | 漏洞验证 |
35
+ | graphql_test | GraphQL 测试 |
36
+ | cloud_storage_test | 云存储测试 |
37
+ | idor_test | IDOR 测试 |
38
+ | sqli_test | SQLi 测试 |
39
+ | auth_test | 认证测试 |
37
40
 
38
41
  ## 测试流程
39
42
 
40
43
  ### Phase 1: 侦察
41
44
  1. browser_collect 采集动态端点
42
45
  2. js_parse 分析 JS 文件
43
- 3. url_discover 发现隐藏端点
46
+ 3. api_fuzz_test 发现隐藏端点
44
47
 
45
48
  ### Phase 2: 分析
46
49
  1. 识别技术栈
@@ -1,8 +1,10 @@
1
1
  ---
2
- version: ">=1.0.0"
3
- requires: ">=1.0.0"
4
- description: 漏洞挖掘专家。专注发现和验证 API 安全漏洞。
2
+ description: 漏洞挖掘专家。专注发现和验证 API 漏洞。
5
3
  mode: subagent
4
+ permission:
5
+ edit: ask
6
+ bash:
7
+ "*": ask
6
8
  ---
7
9
 
8
10
  你是**API漏洞挖掘专家**,专注于发现和验证安全漏洞。
@@ -23,35 +25,17 @@ mode: subagent
23
25
 
24
26
  ### IDOR
25
27
  - 替换 ID: /api/user/1 → /api/user/2
26
- - 水平越权测试
27
- - 垂直越权测试
28
+ - 水平/垂直越权测试
28
29
 
29
30
  ### JWT
30
31
  - 空算法: alg: none
31
32
  - 密钥混淆: HS256 → HS512
32
- - 无签名验证
33
-
34
- ### 敏感数据
35
- - 响应中的密码/密钥
36
- - PII 信息泄露
37
- - 调试端点
38
33
 
39
34
  ## 可用工具
40
35
 
41
- - sqli_test: SQL 注入测试
42
- - idor_test: IDOR 测试
43
- - vuln_verify: 漏洞验证
44
- - api_fuzz_test: 模糊测试
45
-
46
- ## 输出格式
47
-
48
- ```
49
- ## 发现漏洞
50
-
51
- ### {type}
52
- - **端点**: {endpoint}
53
- - **方法**: {method}
54
- - **严重程度**: {severity}
55
- - **PoC**: `{command}`
56
- - **状态**: {status}
57
- ```
36
+ | 工具 | 用途 |
37
+ |------|------|
38
+ | sqli_test | SQL 注入测试 |
39
+ | idor_test | IDOR 测试 |
40
+ | vuln_verify | 漏洞验证 |
41
+ | api_fuzz_test | 模糊测试 |
@@ -1,8 +1,10 @@
1
1
  ---
2
- version: ">=1.0.0"
3
- requires: ">=1.0.0"
4
2
  description: 资源探测专家。专注采集和发现 API 端点。
5
3
  mode: subagent
4
+ permission:
5
+ edit: ask
6
+ bash:
7
+ "*": ask
6
8
  ---
7
9
 
8
10
  你是**API资源探测专家**,专注于发现和采集 API 端点。
@@ -19,38 +21,16 @@ mode: subagent
19
21
  使用 browser_collect 拦截 XHR/Fetch 请求
20
22
 
21
23
  ### 2. JS 静态分析
22
- 使用 js_parse 解析 JavaScript 文件
24
+ 使用 js_parse 解析 JS 文件
23
25
 
24
26
  ### 3. 目录探测
25
- 常见路径:
26
- - /api/v1/*, /graphql
27
- - /swagger, /api-docs
28
- - /.well-known/*
29
-
30
- ## 端点分类
31
-
32
- | 风险 | 类型 | 示例 |
33
- |------|------|------|
34
- | 高 | 认证 | /login, /oauth/* |
35
- | 高 | 数据 | /api/*/list, /search |
36
- | 中 | 用户 | /users, /profile |
37
- | 极高 | 管理 | /admin, /manage |
27
+ 常见路径: /api/v1/*, /graphql, /swagger, /.well-known/*
38
28
 
39
29
  ## 可用工具
40
30
 
41
- - browser_collect: 浏览器采集
42
- - js_parse: JS 文件解析
43
- - api_fuzz_test: 端点探测
44
-
45
- ## 输出格式
46
-
47
- ```
48
- ## 端点发现报告
49
-
50
- - 总数: {count}
51
- - 高风险: {high}
52
- - 中风险: {medium}
53
-
54
- ### 高风险端点
55
- 1. {method} {path} - {reason}
56
- ```
31
+ | 工具 | 用途 |
32
+ |------|------|
33
+ | browser_collect | 浏览器采集 |
34
+ | js_parse | JS 分析 |
35
+ | api_fuzz_test | 模糊测试 |
36
+ | graphql_test | GraphQL 测试 |
@@ -1,8 +1,10 @@
1
1
  ---
2
- version: ">=1.0.0"
3
- requires: ">=1.0.0"
4
2
  description: 漏洞验证专家。验证和确认安全漏洞。
5
3
  mode: subagent
4
+ permission:
5
+ edit: ask
6
+ bash:
7
+ "*": ask
6
8
  ---
7
9
 
8
10
  你是**漏洞验证专家**,专注于验证和确认安全漏洞。
@@ -15,37 +17,16 @@ mode: subagent
15
17
 
16
18
  ## 验证流程
17
19
 
18
- 1. 构造 payload
19
- 2. 发送测试请求
20
- 3. 分析响应
21
- 4. 判断结果
22
- 5. 生成 PoC
20
+ 1. 接收漏洞报告
21
+ 2. 验证漏洞真实性
22
+ 3. 评估风险等级
23
+ 4. 生成 PoC
23
24
 
24
25
  ## 可用工具
25
26
 
26
- - vuln_verify: 漏洞验证
27
- - sqli_test: SQL 注入测试
28
- - idor_test: IDOR 测试
29
- - api_fuzz_test: 模糊测试
30
-
31
- ## 输出格式
32
-
33
- ```
34
- ## 验证结果
35
-
36
- **漏洞类型**: {type}
37
- **端点**: {endpoint}
38
- **验证状态**: CONFIRMED / INVALID / UNCERTAIN
39
- **严重程度**: Critical / High / Medium / Low / Info
40
-
41
- ### 测试步骤
42
- 1. {step}
43
-
44
- ### PoC
45
- ```bash
46
- {command}
47
- ```
48
-
49
- ### 修复建议
50
- {fix}
51
- ```
27
+ | 工具 | 用途 |
28
+ |------|------|
29
+ | vuln_verify | 漏洞验证 |
30
+ | sqli_test | SQL 注入验证 |
31
+ | idor_test | IDOR 验证 |
32
+ | auth_test | 认证问题验证 |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-api-security-testing",
3
- "version": "3.0.8",
3
+ "version": "3.0.9",
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",
package/src/index.ts CHANGED
@@ -1,23 +1,17 @@
1
1
  import type { Plugin } from "@opencode-ai/plugin";
2
2
  import { tool } from "@opencode-ai/plugin";
3
- import { join, dirname, resolve } from "path";
4
- import { existsSync, readFileSync } from "fs";
3
+ import { join } from "path";
4
+ import { existsSync } from "fs";
5
5
 
6
6
  const SKILL_DIR = "skills/api-security-testing";
7
7
  const CORE_DIR = `${SKILL_DIR}/core`;
8
- const AGENTS_DIR = ".config/opencode/agents";
9
- const AGENTS_FILENAME = "AGENTS.md";
10
-
11
- function getSkillPath(ctx: { directory: string }): string {
12
- return join(ctx.directory, SKILL_DIR);
13
- }
14
8
 
15
9
  function getCorePath(ctx: { directory: string }): string {
16
10
  return join(ctx.directory, CORE_DIR);
17
11
  }
18
12
 
19
13
  function checkDeps(ctx: { directory: string }): string {
20
- const skillPath = getSkillPath(ctx);
14
+ const skillPath = join(ctx.directory, SKILL_DIR);
21
15
  const reqFile = join(skillPath, "requirements.txt");
22
16
  if (existsSync(reqFile)) {
23
17
  return `pip install -q -r "${reqFile}" 2>/dev/null; `;
@@ -25,35 +19,6 @@ function checkDeps(ctx: { directory: string }): string {
25
19
  return "";
26
20
  }
27
21
 
28
- function getAgentsDir(): string {
29
- const home = process.env.HOME || process.env.USERPROFILE || "/root";
30
- return join(home, AGENTS_DIR);
31
- }
32
-
33
- function getInjectedAgentsPrompt(): string {
34
- const agentsDir = getAgentsDir();
35
- const agentsPath = join(agentsDir, "api-cyber-supervisor.md");
36
-
37
- if (!existsSync(agentsPath)) {
38
- return "";
39
- }
40
-
41
- try {
42
- const content = readFileSync(agentsPath, "utf-8");
43
- return `
44
-
45
- [API Security Testing Agents Available]
46
- When performing security testing tasks, you can use the following specialized agents:
47
-
48
- ${content}
49
-
50
- To activate these agents, simply mention their name in your response (e.g., "@api-cyber-supervisor" to coordinate security testing).
51
- `;
52
- } catch {
53
- return "";
54
- }
55
- }
56
-
57
22
  async function execShell(ctx: unknown, cmd: string): Promise<string> {
58
23
  const shell = ctx as { $: (strings: TemplateStringsArray, ...expr: unknown[]) => Promise<{ toString(): string }> };
59
24
  const result = await shell.$`${cmd}`;
@@ -63,8 +28,6 @@ async function execShell(ctx: unknown, cmd: string): Promise<string> {
63
28
  const ApiSecurityTestingPlugin: Plugin = async (ctx) => {
64
29
  console.log("[api-security-testing] Plugin loaded");
65
30
 
66
- const injectedSessions = new Set<string>();
67
-
68
31
  return {
69
32
  tool: {
70
33
  api_security_scan: tool({
@@ -274,69 +237,6 @@ print(result)
274
237
  },
275
238
  }),
276
239
  },
277
-
278
- "chat.message": async (input, output) => {
279
- const sessionID = input.sessionID;
280
-
281
- if (!injectedSessions.has(sessionID)) {
282
- injectedSessions.add(sessionID);
283
-
284
- const agentsPrompt = getInjectedAgentsPrompt();
285
- if (agentsPrompt) {
286
- const parts = output.parts as Array<{ type: string; text?: string }>;
287
- const textPart = parts.find(p => p.type === "text");
288
- if (textPart && textPart.text) {
289
- textPart.text += agentsPrompt;
290
- }
291
- }
292
- }
293
- },
294
-
295
- "tool.execute.after": async (input, output) => {
296
- const toolName = input.tool.toLowerCase();
297
- const agentsDir = getAgentsDir();
298
-
299
- if (!existsSync(agentsDir)) return;
300
-
301
- if (toolName === "read") {
302
- const filePath = output.title;
303
- if (!filePath) return;
304
-
305
- const resolved = resolve(filePath);
306
- const dir = dirname(resolved);
307
-
308
- if (!dir.includes(agentsDir)) return;
309
-
310
- const agentsPath = join(agentsDir, AGENTS_FILENAME);
311
- if (!existsSync(agentsPath)) return;
312
-
313
- try {
314
- const content = readFileSync(agentsPath, "utf-8");
315
- output.output += `\n\n[Agents Definition]\n${content}`;
316
- } catch (err) {
317
- console.error("[api-security-testing] Failed to inject agents:", err);
318
- }
319
- }
320
- },
321
-
322
- event: async (input) => {
323
- const { event } = input;
324
-
325
- if (event.type === "session.deleted" || event.type === "session.compacted") {
326
- const props = event.properties as Record<string, unknown> | undefined;
327
- let sessionID: string | undefined;
328
-
329
- if (event.type === "session.deleted") {
330
- sessionID = (props?.info as { id?: string })?.id;
331
- } else {
332
- sessionID = (props?.sessionID ?? (props?.info as { id?: string })?.id) as string | undefined;
333
- }
334
-
335
- if (sessionID) {
336
- injectedSessions.delete(sessionID);
337
- }
338
- }
339
- },
340
240
  };
341
241
  };
342
242
 
@@ -1,106 +0,0 @@
1
- import type { PluginInput } from "@opencode-ai/plugin";
2
- import { existsSync, readFileSync } from "fs";
3
- import { dirname, join, resolve } from "path";
4
-
5
- const AGENTS_FILENAME = "AGENTS.md";
6
- const AGENTS_DIR = ".config/opencode/agents";
7
-
8
- function getHomeDir(): string {
9
- return process.env.HOME || process.env.USERPROFILE || "/root";
10
- }
11
-
12
- export function createDirectoryAgentsInjectorHook(ctx: PluginInput) {
13
- const injectedPaths = new Set<string>();
14
-
15
- function resolveAgentsDir(): string | null {
16
- const home = getHomeDir();
17
- return join(home, AGENTS_DIR);
18
- }
19
-
20
- function findAgentsMdUp(startDir: string, agentsDir: string): string | null {
21
- const home = getHomeDir();
22
- let current = startDir;
23
-
24
- while (true) {
25
- const agentsPath = join(current, AGENTS_FILENAME);
26
- if (existsSync(agentsPath)) {
27
- return agentsPath;
28
- }
29
-
30
- if (current === agentsDir) break;
31
- const parent = dirname(current);
32
- if (parent === current) break;
33
- if (parent === "/" || parent === home) break;
34
- current = parent;
35
- }
36
-
37
- return null;
38
- }
39
-
40
- function getSessionKey(sessionID: string): string {
41
- return `api-sec-inject-${sessionID}`;
42
- }
43
-
44
- const toolExecuteAfter = async (
45
- input: { tool: string; sessionID: string; callID: string },
46
- output: { title: string; output: string; metadata: unknown }
47
- ) => {
48
- const toolName = input.tool.toLowerCase();
49
- const agentsDir = resolveAgentsDir();
50
-
51
- if (!agentsDir || !existsSync(agentsDir)) return;
52
-
53
- if (toolName === "read") {
54
- const filePath = output.title;
55
- if (!filePath) return;
56
-
57
- const resolved = resolve(filePath);
58
- const dir = dirname(resolved);
59
-
60
- if (!dir.includes(agentsDir)) return;
61
-
62
- const cacheKey = getSessionKey(input.sessionID);
63
- if (injectedPaths.has(cacheKey + resolved)) return;
64
-
65
- const agentsPath = findAgentsMdUp(dir, agentsDir);
66
- if (!agentsPath) return;
67
-
68
- try {
69
- const content = readFileSync(agentsPath, "utf-8");
70
- output.output += `\n\n[Auto-injected from ${AGENTS_FILENAME}]\n${content}`;
71
- injectedPaths.add(cacheKey + resolved);
72
- } catch (err) {
73
- console.error("[api-security-testing] Failed to inject agents:", err);
74
- }
75
- }
76
- };
77
-
78
- const eventHandler = async (input: { event: { type: string; properties?: unknown } }) => {
79
- const { event } = input;
80
-
81
- if (event.type === "session.deleted" || event.type === "session.compacted") {
82
- const props = event.properties as Record<string, unknown> | undefined;
83
- let sessionID: string | undefined;
84
-
85
- if (event.type === "session.deleted") {
86
- sessionID = (props?.info as { id?: string })?.id;
87
- } else {
88
- sessionID = (props?.sessionID ?? (props?.info as { id?: string })?.id) as string | undefined;
89
- }
90
-
91
- if (sessionID) {
92
- const cacheKey = getSessionKey(sessionID);
93
- for (const key of injectedPaths.keys()) {
94
- if (key.startsWith(cacheKey)) {
95
- injectedPaths.delete(key);
96
- }
97
- }
98
- }
99
- }
100
- };
101
-
102
- return {
103
- "tool.execute.after": toolExecuteAfter,
104
- event: eventHandler,
105
- };
106
- }