opencode-api-security-testing 2.0.0 → 2.1.1
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/README.md +30 -24
- package/SKILL.md +1797 -0
- package/core/advanced_recon.py +788 -0
- package/core/agentic_analyzer.py +445 -0
- package/core/analyzers/api_parser.py +210 -0
- package/core/analyzers/response_analyzer.py +212 -0
- package/core/analyzers/sensitive_finder.py +184 -0
- package/core/api_fuzzer.py +422 -0
- package/core/api_interceptor.py +525 -0
- package/core/api_parser.py +955 -0
- package/core/browser_tester.py +479 -0
- package/core/cloud_storage_tester.py +1330 -0
- package/core/collectors/__init__.py +23 -0
- package/core/collectors/api_path_finder.py +300 -0
- package/core/collectors/browser_collect.py +645 -0
- package/core/collectors/browser_collector.py +411 -0
- package/core/collectors/http_client.py +111 -0
- package/core/collectors/js_collector.py +490 -0
- package/core/collectors/js_parser.py +780 -0
- package/core/collectors/url_collector.py +319 -0
- package/core/context_manager.py +682 -0
- package/core/deep_api_tester_v35.py +844 -0
- package/core/deep_api_tester_v55.py +366 -0
- package/core/dynamic_api_analyzer.py +532 -0
- package/core/http_client.py +179 -0
- package/core/models.py +296 -0
- package/core/orchestrator.py +890 -0
- package/core/prerequisite.py +227 -0
- package/core/reasoning_engine.py +1042 -0
- package/core/response_classifier.py +606 -0
- package/core/runner.py +938 -0
- package/core/scan_engine.py +599 -0
- package/core/skill_executor.py +435 -0
- package/core/skill_executor_v2.py +670 -0
- package/core/skill_executor_v3.py +704 -0
- package/core/smart_analyzer.py +687 -0
- package/core/strategy_pool.py +707 -0
- package/core/testers/auth_tester.py +264 -0
- package/core/testers/idor_tester.py +200 -0
- package/core/testers/sqli_tester.py +211 -0
- package/core/testing_loop.py +655 -0
- package/core/utils/base_path_dict.py +255 -0
- package/core/utils/payload_lib.py +167 -0
- package/core/utils/ssrf_detector.py +220 -0
- package/core/verifiers/vuln_verifier.py +536 -0
- package/package.json +17 -13
- package/references/asset-discovery.md +119 -612
- package/references/graphql-guidance.md +65 -641
- package/references/intake.md +84 -0
- package/references/report-template.md +131 -38
- package/references/rest-guidance.md +55 -526
- package/references/severity-model.md +52 -264
- package/references/test-matrix.md +65 -263
- package/references/validation.md +53 -400
- package/scripts/postinstall.js +46 -0
- package/src/index.ts +259 -275
- package/agents/cyber-supervisor.md +0 -55
- package/agents/probing-miner.md +0 -42
- package/agents/resource-specialist.md +0 -31
- package/commands/api-security-testing-scan.md +0 -59
- package/commands/api-security-testing-test.md +0 -49
- package/commands/api-security-testing.md +0 -72
- package/tsconfig.json +0 -17
package/references/validation.md
CHANGED
|
@@ -1,425 +1,78 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Validation Guidance
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
验证和分类发现。
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
发现 → 分析 → 验证 → 定级 → 报告
|
|
5
|
+
## 报告标准
|
|
7
6
|
|
|
8
|
-
|
|
9
|
-
│ 发现 (Discover) │
|
|
10
|
-
│ - 可疑响应差异 │
|
|
11
|
-
│ - 异常状态码 │
|
|
12
|
-
│ - 敏感信息暴露 │
|
|
13
|
-
└─────────────┬───────────────────┘
|
|
14
|
-
▼
|
|
15
|
-
┌─────────────────────────────────┐
|
|
16
|
-
│ 分析 (Analyze) │
|
|
17
|
-
│ - 多次请求确认差异稳定 │
|
|
18
|
-
│ - 对比正常/异常请求 │
|
|
19
|
-
│ - 排除 WAF/路由/认证 │
|
|
20
|
-
└─────────────┬───────────────────┘
|
|
21
|
-
▼
|
|
22
|
-
┌─────────────────────────────────┐
|
|
23
|
-
│ 验证 (Verify) │
|
|
24
|
-
│ - 10 维度检查 │
|
|
25
|
-
│ - 证据收集 │
|
|
26
|
-
│ - 确认或排除 │
|
|
27
|
-
└─────────────┬───────────────────┘
|
|
28
|
-
▼
|
|
29
|
-
┌─────────────────────────────────┐
|
|
30
|
-
│ 定级 (Severity) │
|
|
31
|
-
│ - CVSS 评分 │
|
|
32
|
-
│ - 业务影响评估 │
|
|
33
|
-
│ - 修复优先级 │
|
|
34
|
-
└─────────────┬───────────────────┘
|
|
35
|
-
▼
|
|
36
|
-
┌─────────────────────────────────┐
|
|
37
|
-
│ 报告 (Report) │
|
|
38
|
-
│ - 漏洞详情 │
|
|
39
|
-
│ - 复现步骤 │
|
|
40
|
-
│ - 修复建议 │
|
|
41
|
-
└─────────────────────────────────┘
|
|
42
|
-
```
|
|
7
|
+
仅报告有足够支持的问题:
|
|
43
8
|
|
|
44
|
-
|
|
9
|
+
### 必须包含
|
|
45
10
|
|
|
46
|
-
|
|
11
|
+
- **受影响资产**: 具体的 API endpoint 或操作
|
|
12
|
+
- **证据**: 请求/响应样本
|
|
13
|
+
- **复现路径**: 清晰的步骤
|
|
14
|
+
- **影响**: 现实世界的影响
|
|
15
|
+
- **置信级别**: 确认/高/中/低/假设
|
|
47
16
|
|
|
48
|
-
|
|
49
|
-
|------|--------|----------|----------|
|
|
50
|
-
| **D1 响应类型** | 是 JSON 还是 HTML? | JSON 响应包含业务数据 | HTML 页面 (WAF/SPA) |
|
|
51
|
-
| **D2 状态码** | 状态码是否合理? | 与漏洞场景匹配 | 302 重定向 |
|
|
52
|
-
| **D3 响应长度** | 响应长度是否正常? | 长度 > 100 字节 | 过短响应 (拦截) |
|
|
53
|
-
| **D4 WAF 识别** | 是否为 WAF 拦截? | 无 WAF 特征 | HTML 拦截页 |
|
|
54
|
-
| **D5 敏感信息** | 是否包含敏感字段? | 字段不属于测试数据 | 测试假数据 |
|
|
55
|
-
| **D6 一致性** | 多次请求是否一致? | 多次响应相同 | 不稳定响应 |
|
|
56
|
-
| **D7 SQL 注入** | 是否包含 SQL 错误? | 无 SQL 错误特征 | 通用错误信息 |
|
|
57
|
-
| **D8 IDOR** | 是否返回他人数据? | 返回数据属于他人 | 返回自己的数据 |
|
|
58
|
-
| **D9 认证绕过** | 是否返回 token/session? | Token 有效且可用 | 无效/过期 Token |
|
|
59
|
-
| **D10 信息泄露** | 是否泄露非公开信息? | 信息非公开 | 公开信息 |
|
|
17
|
+
### 证据不完整时
|
|
60
18
|
|
|
61
|
-
|
|
19
|
+
- 标记为假设 (hypothesis)、弱信号 (weak signal) 或可能问题 (likely issue)
|
|
20
|
+
- 明确解释确认所需内容
|
|
62
21
|
|
|
63
|
-
|
|
22
|
+
### 不要
|
|
64
23
|
|
|
65
|
-
|
|
24
|
+
- 从模糊行为夸大严重性
|
|
25
|
+
- 基于不完整的证据做强声明
|
|
26
|
+
- 假设最坏情况
|
|
66
27
|
|
|
67
|
-
|
|
68
|
-
# 验证标准
|
|
69
|
-
SQLI_VERIFICATION = {
|
|
70
|
-
# 必须满足
|
|
71
|
-
'required': [
|
|
72
|
-
'响应包含数据库错误信息',
|
|
73
|
-
'UNION 查询有回显',
|
|
74
|
-
'时间盲注有延迟',
|
|
75
|
-
],
|
|
76
|
-
# 参考指标
|
|
77
|
-
'indicators': [
|
|
78
|
-
'错误信息包含 SQL 关键词',
|
|
79
|
-
'响应时间 > 5秒 (盲注)',
|
|
80
|
-
'页面结构与正常响应不同 (UNION)',
|
|
81
|
-
],
|
|
82
|
-
# 排除条件
|
|
83
|
-
'exclude': [
|
|
84
|
-
'通用错误信息 (无 SQL 关键词)',
|
|
85
|
-
'WAF 拦截页面',
|
|
86
|
-
'响应时间正常但无其他特征',
|
|
87
|
-
]
|
|
88
|
-
}
|
|
28
|
+
## 置信级别
|
|
89
29
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
# 3. 对比分析
|
|
99
|
-
indicators = {
|
|
100
|
-
'sql_error': contains_sql_error(inject.text),
|
|
101
|
-
'response_diff': baseline.text != inject.text,
|
|
102
|
-
'data_leak': extract_data(inject.text), # UNION 注入时
|
|
103
|
-
'time_delay': measure_time(inject), # 盲注时
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
# 4. 综合判断
|
|
107
|
-
if indicators['sql_error'] or indicators['data_leak'] or indicators['time_delay'] > 5:
|
|
108
|
-
return True, indicators
|
|
109
|
-
return False, indicators
|
|
110
|
-
```
|
|
30
|
+
| 级别 | 标准 |
|
|
31
|
+
|------|------|
|
|
32
|
+
| **确认 (Confirmed)** | 完整的 PoC、明确的证据 |
|
|
33
|
+
| **高 (High)** | 强指标、合理推断 |
|
|
34
|
+
| **中 (Medium)** | 中等指标、需要更多验证 |
|
|
35
|
+
| **低 (Low)** | 弱指标、可能是误报 |
|
|
36
|
+
| **假设 (Hypothesis)** | 基于观察的推断、需要进一步调查 |
|
|
111
37
|
|
|
112
|
-
|
|
38
|
+
## 影响评估
|
|
113
39
|
|
|
114
|
-
|
|
115
|
-
# 验证标准
|
|
116
|
-
XSS_VERIFICATION = {
|
|
117
|
-
'required': [
|
|
118
|
-
'Payload 未经处理回显',
|
|
119
|
-
'可执行 JavaScript',
|
|
120
|
-
],
|
|
121
|
-
'indicators': [
|
|
122
|
-
'Payload 在响应中完整回显',
|
|
123
|
-
'<script> 标签未转义',
|
|
124
|
-
'事件处理器未被过滤',
|
|
125
|
-
],
|
|
126
|
-
'exclude': [
|
|
127
|
-
'HTML 实体转义',
|
|
128
|
-
'<script> 被删除/过滤',
|
|
129
|
-
'CSP 阻止执行',
|
|
130
|
-
]
|
|
131
|
-
}
|
|
40
|
+
### 考虑
|
|
132
41
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
# 2. 检查回显
|
|
139
|
-
if payload in resp.text:
|
|
140
|
-
# 3. 检查是否是存储型
|
|
141
|
-
# 用另一请求检查是否持久化
|
|
142
|
-
resp2 = requests.get(url) # 再次访问
|
|
143
|
-
|
|
144
|
-
if payload in resp2.text:
|
|
145
|
-
return True, {'type': 'stored', 'persisted': True}
|
|
146
|
-
return True, {'type': 'reflected', 'persisted': False}
|
|
147
|
-
|
|
148
|
-
return False, {'type': None}
|
|
149
|
-
```
|
|
42
|
+
- 攻击复杂度
|
|
43
|
+
- 用户交互需求
|
|
44
|
+
- 数据敏感性
|
|
45
|
+
- 受影响用户数量
|
|
46
|
+
- 财务/合规影响
|
|
150
47
|
|
|
151
|
-
###
|
|
48
|
+
### 避免
|
|
152
49
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
'required': [
|
|
157
|
-
'用自己的 Token 访问他人资源',
|
|
158
|
-
'返回他人敏感数据',
|
|
159
|
-
],
|
|
160
|
-
'indicators': [
|
|
161
|
-
'资源 ID 可枚举',
|
|
162
|
-
'响应包含不同用户数据',
|
|
163
|
-
'无权限检查错误',
|
|
164
|
-
],
|
|
165
|
-
'exclude': [
|
|
166
|
-
'返回 401/403',
|
|
167
|
-
'返回空数据',
|
|
168
|
-
'返回自己的数据',
|
|
169
|
-
]
|
|
170
|
-
}
|
|
50
|
+
- 夸大威胁
|
|
51
|
+
- 基于假设的影响
|
|
52
|
+
- 不切实际的利用场景
|
|
171
53
|
|
|
172
|
-
|
|
173
|
-
def verify_idor(base_url, token, victim_resource_id):
|
|
174
|
-
# 1. 自己的资源 (基线)
|
|
175
|
-
headers = {'Authorization': f'Bearer {token}'}
|
|
176
|
-
my_resource = requests.get(
|
|
177
|
-
f'{base_url}/resource/1',
|
|
178
|
-
headers=headers
|
|
179
|
-
)
|
|
180
|
-
|
|
181
|
-
# 2. 他人的资源 (测试)
|
|
182
|
-
victim_resource = requests.get(
|
|
183
|
-
f'{base_url}/resource/{victim_resource_id}',
|
|
184
|
-
headers=headers
|
|
185
|
-
)
|
|
186
|
-
|
|
187
|
-
# 3. 对比分析
|
|
188
|
-
if victim_resource.status_code == 200:
|
|
189
|
-
my_data = my_resource.json()
|
|
190
|
-
victim_data = victim_resource.json()
|
|
191
|
-
|
|
192
|
-
# 检查是否是不同用户的数据
|
|
193
|
-
if my_data.get('userId') != victim_data.get('userId'):
|
|
194
|
-
return True, {
|
|
195
|
-
'my_user': my_data.get('userId'),
|
|
196
|
-
'victim_user': victim_data.get('userId'),
|
|
197
|
-
'leaked_fields': list(victim_data.keys())
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
return False, {'status': victim_resource.status_code}
|
|
201
|
-
```
|
|
54
|
+
## 验证技术
|
|
202
55
|
|
|
203
|
-
###
|
|
56
|
+
### 认证问题
|
|
204
57
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
'alg_none': {
|
|
209
|
-
'required': ['使用 alg:none 的 Token 可正常使用'],
|
|
210
|
-
'test': '去除签名的 Token 可通过验证',
|
|
211
|
-
},
|
|
212
|
-
'key_confusion': {
|
|
213
|
-
'required': ['使用公钥作为对称密钥可伪造 Token'],
|
|
214
|
-
'test': 'RS256 算法可被转换为 HS256',
|
|
215
|
-
},
|
|
216
|
-
'weak_secret': {
|
|
217
|
-
'required': ['弱密钥可被暴力破解'],
|
|
218
|
-
'test': '常见密钥可成功签名',
|
|
219
|
-
},
|
|
220
|
-
'kid_injection': {
|
|
221
|
-
'required': ['kid 参数存在 SQL/NoSQL 注入'],
|
|
222
|
-
'test': '利用 kid 注入读取任意密钥',
|
|
223
|
-
},
|
|
224
|
-
}
|
|
58
|
+
- 验证 token 伪造是否可能
|
|
59
|
+
- 测试会话管理缺陷
|
|
60
|
+
- 确认账户接管场景
|
|
225
61
|
|
|
226
|
-
|
|
227
|
-
header = decode_header(token)
|
|
228
|
-
if header.get('alg') == 'none':
|
|
229
|
-
# 尝试去除签名
|
|
230
|
-
unsigned_token = create_unsigned_token(header, payload)
|
|
231
|
-
if is_valid(unsigned_token):
|
|
232
|
-
return True, {'alg': 'none', 'exploitable': True}
|
|
233
|
-
return False, {}
|
|
234
|
-
```
|
|
62
|
+
### 授权问题
|
|
235
63
|
|
|
236
|
-
|
|
64
|
+
- 测试 IDOR 是否可利用
|
|
65
|
+
- 验证水平/垂直越权
|
|
66
|
+
- 确认权限提升路径
|
|
237
67
|
|
|
238
|
-
|
|
239
|
-
# 验证标准
|
|
240
|
-
SENSITIVE_DATA_VERIFICATION = {
|
|
241
|
-
'password': {
|
|
242
|
-
'required': ['响应包含明文密码'],
|
|
243
|
-
'severity': 'Critical',
|
|
244
|
-
'exclude': ['密码已加密/哈希', '测试数据密码'],
|
|
245
|
-
},
|
|
246
|
-
'token': {
|
|
247
|
-
'required': ['响应包含有效 Token'],
|
|
248
|
-
'severity': 'High',
|
|
249
|
-
'exclude': ['过期 Token', '测试 Token'],
|
|
250
|
-
},
|
|
251
|
-
'api_key': {
|
|
252
|
-
'required': ['响应包含有效 API 密钥'],
|
|
253
|
-
'severity': 'High',
|
|
254
|
-
'exclude': ['测试环境密钥'],
|
|
255
|
-
},
|
|
256
|
-
'internal_ip': {
|
|
257
|
-
'required': ['响应包含内网 IP 地址'],
|
|
258
|
-
'severity': 'Medium',
|
|
259
|
-
},
|
|
260
|
-
'internal_url': {
|
|
261
|
-
'required': ['响应包含内部系统 URL'],
|
|
262
|
-
'severity': 'Medium',
|
|
263
|
-
},
|
|
264
|
-
}
|
|
68
|
+
### 输入处理
|
|
265
69
|
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
'token', 'api_key', 'apikey', 'private_key',
|
|
270
|
-
'ssn', 'id_card', 'phone', 'email',
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
if field_name.lower() in sensitive_fields:
|
|
274
|
-
# 检查值是否存在
|
|
275
|
-
value = resp.json().get(field_name)
|
|
276
|
-
if value and value not in ['', 'null', 'undefined']:
|
|
277
|
-
return True, {'field': field_name, 'severity': get_severity(field_name)}
|
|
278
|
-
|
|
279
|
-
return False, {}
|
|
280
|
-
```
|
|
70
|
+
- 使用安全 payload 验证
|
|
71
|
+
- 确认漏洞触发条件
|
|
72
|
+
- 评估利用难度
|
|
281
73
|
|
|
282
|
-
|
|
74
|
+
### 数据泄露
|
|
283
75
|
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
```python
|
|
289
|
-
WAF_PATTERNS = [
|
|
290
|
-
# 通用 WAF
|
|
291
|
-
r'(?i)(waf|firewall|attack|blocked|intercepted)',
|
|
292
|
-
r'(?i)(forbidden|access.*denied|security)',
|
|
293
|
-
# 特定 WAF
|
|
294
|
-
r'Aliyun',
|
|
295
|
-
r'Tencet',
|
|
296
|
-
r'AWS.*WAF',
|
|
297
|
-
r'Cloudflare',
|
|
298
|
-
r'Incapsula',
|
|
299
|
-
]
|
|
300
|
-
|
|
301
|
-
def is_waf_response(resp):
|
|
302
|
-
content = resp.text
|
|
303
|
-
for pattern in WAF_PATTERNS:
|
|
304
|
-
if re.search(pattern, content):
|
|
305
|
-
return True
|
|
306
|
-
return False
|
|
307
|
-
```
|
|
308
|
-
|
|
309
|
-
### 规则 2: SPA 路由识别
|
|
310
|
-
|
|
311
|
-
```python
|
|
312
|
-
SPA_PATTERNS = [
|
|
313
|
-
r'<div id="app">',
|
|
314
|
-
r'<div id="root">',
|
|
315
|
-
r'__VUE__',
|
|
316
|
-
r'__NUXT__',
|
|
317
|
-
r'ReactDOM',
|
|
318
|
-
r'webpack',
|
|
319
|
-
]
|
|
320
|
-
|
|
321
|
-
def is_spa_response(resp):
|
|
322
|
-
content = resp.text
|
|
323
|
-
for pattern in SPA_PATTERNS:
|
|
324
|
-
if re.search(pattern, content):
|
|
325
|
-
return True
|
|
326
|
-
return False
|
|
327
|
-
```
|
|
328
|
-
|
|
329
|
-
### 规则 3: 统一错误页识别
|
|
330
|
-
|
|
331
|
-
```python
|
|
332
|
-
ERROR_PAGE_PATTERNS = [
|
|
333
|
-
r'页面不存在|404 Not Found',
|
|
334
|
-
r'服务器错误|500 Internal Server Error',
|
|
335
|
-
r'请求超时|Timeout',
|
|
336
|
-
]
|
|
337
|
-
|
|
338
|
-
def is_error_page(resp):
|
|
339
|
-
for pattern in ERROR_PAGE_PATTERNS:
|
|
340
|
-
if re.search(pattern, resp.text):
|
|
341
|
-
return True
|
|
342
|
-
return False
|
|
343
|
-
```
|
|
344
|
-
|
|
345
|
-
---
|
|
346
|
-
|
|
347
|
-
## 验证结果记录
|
|
348
|
-
|
|
349
|
-
### 漏洞验证报告模板
|
|
350
|
-
|
|
351
|
-
```markdown
|
|
352
|
-
## 漏洞验证记录
|
|
353
|
-
|
|
354
|
-
### 基本信息
|
|
355
|
-
- **漏洞类型**: SQL 注入
|
|
356
|
-
- **测试目标**: GET /api/user?id=1
|
|
357
|
-
- **测试时间**: 2026-04-03 10:30:00
|
|
358
|
-
- **验证人员**: Agent
|
|
359
|
-
|
|
360
|
-
### 验证过程
|
|
361
|
-
1. **原始请求**
|
|
362
|
-
- 请求: GET /api/user?id=1
|
|
363
|
-
- 响应: 200 OK, {"userId": 1, "name": "张三"}
|
|
364
|
-
|
|
365
|
-
2. **Payload 测试**
|
|
366
|
-
- Payload: 1' OR '1'='1
|
|
367
|
-
- 请求: GET /api/user?id=1' OR '1'='1
|
|
368
|
-
- 响应: 200 OK, {"userId": 1, "name": "张三"}
|
|
369
|
-
- 响应: [{"userId": 1}, {"userId": 2}, {"userId": 3}]
|
|
370
|
-
|
|
371
|
-
3. **对比分析**
|
|
372
|
-
- 原始响应: 1 条记录
|
|
373
|
-
- 注入响应: 3 条记录
|
|
374
|
-
- **差异确认**: 存在 SQL 注入
|
|
375
|
-
|
|
376
|
-
### 维度评分
|
|
377
|
-
| 维度 | 得分 | 说明 |
|
|
378
|
-
|------|------|------|
|
|
379
|
-
| D1 响应类型 | 15/15 | JSON 响应正常 |
|
|
380
|
-
| D2 状态码 | 15/15 | 200 OK |
|
|
381
|
-
| D3 响应长度 | 18/20 | 长度增加 |
|
|
382
|
-
| D4 WAF | 20/20 | 无 WAF 特征 |
|
|
383
|
-
| D5 敏感信息 | 15/20 | 数据泄露 |
|
|
384
|
-
| D6 一致性 | 15/15 | 多次一致 |
|
|
385
|
-
| D7 SQL注入 | 25/25 | 确认注入 |
|
|
386
|
-
| D8 IDOR | 15/15 | N/A |
|
|
387
|
-
| D9 认证绕过 | 15/15 | N/A |
|
|
388
|
-
| D10 信息泄露 | 10/20 | 泄露用户列表 |
|
|
389
|
-
|
|
390
|
-
### 最终结论
|
|
391
|
-
- **漏洞确认**: ✅ 是
|
|
392
|
-
- **CVSS**: 8.6 (High)
|
|
393
|
-
- **风险等级**: High
|
|
394
|
-
```
|
|
395
|
-
|
|
396
|
-
---
|
|
397
|
-
|
|
398
|
-
## 验证检查清单
|
|
399
|
-
|
|
400
|
-
```
|
|
401
|
-
□ 基础验证
|
|
402
|
-
□ 多次请求确认差异稳定
|
|
403
|
-
□ 对比正常/异常响应
|
|
404
|
-
□ 排除 WAF/安全设备
|
|
405
|
-
□ 排除 SPA 路由
|
|
406
|
-
□ 排除测试数据
|
|
407
|
-
|
|
408
|
-
□ 类型验证
|
|
409
|
-
□ SQL 注入: 数据库错误/数据泄露/时间延迟
|
|
410
|
-
□ XSS: Payload 回显/JavaScript 执行
|
|
411
|
-
□ IDOR: 跨用户数据访问
|
|
412
|
-
□ JWT: 算法攻击/密钥破解
|
|
413
|
-
□ SSRF: 内网访问/元数据获取
|
|
414
|
-
|
|
415
|
-
□ 证据收集
|
|
416
|
-
□ 请求/响应截图
|
|
417
|
-
□ Payload 记录
|
|
418
|
-
□ 时间戳记录
|
|
419
|
-
□ 关键响应内容
|
|
420
|
-
|
|
421
|
-
□ 定级评估
|
|
422
|
-
□ CVSS 计算
|
|
423
|
-
□ 业务影响评估
|
|
424
|
-
□ 修复优先级
|
|
425
|
-
```
|
|
76
|
+
- 确认敏感数据暴露
|
|
77
|
+
- 评估信息价值
|
|
78
|
+
- 检查数据聚合风险
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, cpSync, rmSync, readdirSync, statSync } from "fs";
|
|
2
|
+
import { join, dirname } from "path";
|
|
3
|
+
import { fileURLToPath } from "url";
|
|
4
|
+
|
|
5
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
6
|
+
const __dirname = dirname(__filename);
|
|
7
|
+
const packageRoot = __dirname;
|
|
8
|
+
|
|
9
|
+
const OPENCODE_DIR = process.env.OPENCODE_CONFIG_DIR || join(process.env.HOME || "/root", ".config/opencode");
|
|
10
|
+
const SKILL_DIR = join(OPENCODE_DIR, "skills/api-security-testing");
|
|
11
|
+
|
|
12
|
+
function copyRecursive(src, dest) {
|
|
13
|
+
if (!existsSync(src)) {
|
|
14
|
+
console.warn(`[api-security-testing] Warning: ${src} does not exist, skipping`);
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const stat = statSync(src);
|
|
19
|
+
if (stat.isDirectory()) {
|
|
20
|
+
if (!existsSync(dest)) {
|
|
21
|
+
mkdirSync(dest, { recursive: true });
|
|
22
|
+
}
|
|
23
|
+
for (const entry of readdirSync(src)) {
|
|
24
|
+
copyRecursive(join(src, entry), join(dest, entry));
|
|
25
|
+
}
|
|
26
|
+
} else {
|
|
27
|
+
cpSync(src, dest, { force: true });
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
console.log("[api-security-testing] Setting up skill files...");
|
|
32
|
+
|
|
33
|
+
try {
|
|
34
|
+
copyRecursive(join(packageRoot, "core"), join(SKILL_DIR, "core"));
|
|
35
|
+
copyRecursive(join(packageRoot, "references"), join(SKILL_DIR, "references"));
|
|
36
|
+
|
|
37
|
+
const skillMdSrc = join(packageRoot, "SKILL.md");
|
|
38
|
+
if (existsSync(skillMdSrc)) {
|
|
39
|
+
cpSync(skillMdSrc, join(SKILL_DIR, "SKILL.md"), { force: true });
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
console.log("[api-security-testing] Skill files installed to:", SKILL_DIR);
|
|
43
|
+
} catch (error) {
|
|
44
|
+
console.error("[api-security-testing] Error during installation:", error.message);
|
|
45
|
+
process.exit(1);
|
|
46
|
+
}
|