fix(core): 修复 Plan Agent 通过 heredoc 绕过写入限制的安全漏洞

- 重排 bash 权限规则顺序,deny 规则置于 allow 规则之前
- 添加 heredoc 重定向检测规则 (* << *)
- 新增 checkRedirectInRawCommand 预检函数,在 tree-sitter 解析前检测重定向
- 禁用 Plan Agent 的 tool_search 工具,防止动态发现写入工具
- 添加更多危险命令: ln, install, truncate, dd, tee
This commit is contained in:
2025-12-16 11:23:02 +08:00
parent e698ec2a64
commit 70394ed06c
2 changed files with 89 additions and 32 deletions
+41
View File
@@ -95,6 +95,35 @@ export function matchRules(
return matchSingleCommand(parsed, rules, defaultAction);
}
/**
* 检查原始命令字符串是否包含危险的重定向操作
* 这是一个快速预检,在 tree-sitter 解析之前进行
*/
function checkRedirectInRawCommand(
command: string,
rules: PermissionRule[]
): { action: PermissionAction; matchedPattern?: string } | null {
// 检查重定向相关的 deny 规则
const redirectPatterns = ['* > *', '* >> *', '* << *'];
for (const rule of rules) {
if (rule.action === 'deny' && redirectPatterns.includes(rule.pattern)) {
// 根据模式检查原始命令
if (rule.pattern === '* > *' && / > /.test(command) && !/ >> /.test(command)) {
return { action: 'deny', matchedPattern: rule.pattern };
}
if (rule.pattern === '* >> *' && / >> /.test(command)) {
return { action: 'deny', matchedPattern: rule.pattern };
}
if (rule.pattern === '* << *' && / << /.test(command)) {
return { action: 'deny', matchedPattern: rule.pattern };
}
}
}
return null;
}
/**
* 使用 tree-sitter 解析并检查所有命令的权限(异步版本)
* 返回最严格的权限要求
@@ -109,6 +138,18 @@ export async function matchRulesAsync(
allCommands: ParsedCommand[];
askPatterns: string[];
}> {
// 首先检查原始命令中的重定向操作(这是安全关键检查,必须在解析之前进行)
const redirectCheck = checkRedirectInRawCommand(command, rules);
if (redirectCheck) {
// 如果检测到重定向被拒绝,直接返回
return {
action: redirectCheck.action,
matchedPattern: redirectCheck.matchedPattern,
allCommands: [parseCommandSimple(command)],
askPatterns: [],
};
}
const result = await parseBashCommand(command);
// 如果解析失败,降级到简单解析