feat: 升级至 v0.3.16 — 工单修复 51 项 + 审查修复 30 项(安全加固/适配器/工具系统/数据层/前端)

This commit is contained in:
2026-07-22 10:31:13 +08:00
parent 516d8a728f
commit 2c2ca4a692
43 changed files with 1454 additions and 301 deletions
+71 -4
View File
@@ -157,13 +157,32 @@ export class PolicyEngine {
argsStr = String(args);
}
// #14 修复: 深度递归扫描所有字符串字段值,防止 Unicode 转义/嵌套对象/字符串拼接绕过
// 原 JSON.stringify 后整体正则匹配可被 \u0029 编码、嵌套对象伪装、正则注入等方式绕过
// 现对每个字符串字段值单独匹配,同时保留整体 argsStr 兜底匹配
const stringValues = this.deepScanStrings(args);
// v0.2.0: allowedPatterns 白名单校验 — 若定义了白名单,参数必须匹配其中之一
// #14: 字段级匹配 + 整体兜底,任一匹配即通过
if (policy.allowedPatterns && policy.allowedPatterns.length > 0) {
let matchedAllowed = false;
for (const pattern of policy.allowedPatterns) {
if (pattern.test(argsStr)) {
matchedAllowed = true;
break;
// 先做字段级匹配
for (const val of stringValues) {
for (const pattern of policy.allowedPatterns) {
if (pattern.test(val)) {
matchedAllowed = true;
break;
}
}
if (matchedAllowed) break;
}
// 兜底:整体 argsStr 匹配
if (!matchedAllowed) {
for (const pattern of policy.allowedPatterns) {
if (pattern.test(argsStr)) {
matchedAllowed = true;
break;
}
}
}
if (!matchedAllowed) {
@@ -176,7 +195,22 @@ export class PolicyEngine {
}
}
// #14 修复: deniedPatterns 字段级深度扫描 — 对每个字符串值单独匹配
// 防止危险内容隐藏在嵌套对象或 Unicode 编码中绕过整体 stringify 匹配
if (policy.deniedPatterns) {
for (const val of stringValues) {
for (const pattern of policy.deniedPatterns) {
if (pattern.test(val)) {
return {
authorized: false,
reason: 'Command blocked by security policy',
level: policy.requiredLevel,
requiresConfirmation: false,
};
}
}
}
// 兜底:整体 argsStr 匹配(保留原有行为,捕获跨字段拼接的危险模式)
for (const pattern of policy.deniedPatterns) {
if (pattern.test(argsStr)) {
return {
@@ -264,4 +298,37 @@ export class PolicyEngine {
// v0.3.0 修复: cleanupFrequencyRecords 已删除 — checkFrequency 和 recordCall 已做内联清理,
// 该方法属于死代码,删除以减少维护负担
/**
* #14 修复: 深度递归扫描对象,提取所有字符串字段值
*
* 替代 JSON.stringify 后整体正则匹配的方式,防止:
* - Unicode 转义绕过(\u0029 等编码)
* - 嵌套对象伪装({a: {b: 'dangerous'}}
* - 字符串拼接绕过('rm ' + '-rf /' 在 stringify 后是合法字符串)
* - 正则注入(输入中包含正则元字符破坏匹配逻辑)
*
* @param obj 待扫描的对象
* @returns 所有字符串字段值的数组
*/
// 审查修复: 添加 visited Set 参数防止循环引用导致无限递归栈溢出
private deepScanStrings(obj: unknown, visited: Set<unknown> = new Set()): string[] {
const results: string[] = [];
if (typeof obj === 'string') {
results.push(obj);
} else if (Array.isArray(obj)) {
if (visited.has(obj)) return results;
visited.add(obj);
for (const item of obj) {
results.push(...this.deepScanStrings(item, visited));
}
} else if (obj && typeof obj === 'object') {
if (visited.has(obj)) return results;
visited.add(obj);
for (const v of Object.values(obj)) {
results.push(...this.deepScanStrings(v, visited));
}
}
return results;
}
}