feat: 升级至 v0.3.16 — 工单修复 51 项 + 审查修复 30 项(安全加固/适配器/工具系统/数据层/前端)
This commit is contained in:
@@ -29,6 +29,43 @@ import {
|
||||
FILE_TOOL_TIMEOUT_MS,
|
||||
} from './file-guard';
|
||||
|
||||
/**
|
||||
* #45 修复: 检测潜在灾难性正则模式(ReDoS 风险)
|
||||
*
|
||||
* 灾难性回溯通常由以下模式引起:
|
||||
* - 嵌套量词:(a+)+、(a*)*、(a+)*
|
||||
* - 重叠量词:a+a+、a+.*a+(两个量词之间无固定字符分隔)
|
||||
* - 交替分支加量词:(a|a)*
|
||||
*
|
||||
* 这些模式在长字符串上执行时间指数级增长,可阻塞主进程
|
||||
*
|
||||
* @param pattern 用户提供的正则模式字符串
|
||||
* @returns true 如果检测到潜在灾难性模式
|
||||
*/
|
||||
function isPotentiallyCatastrophicRegex(pattern: string): boolean {
|
||||
// 审查修复: 放宽规则减少误报,补充漏报检测
|
||||
|
||||
// 1. 嵌套量词(捕获组内量词+外层量词)
|
||||
// 审查修复: 区分外层量词类型 — 外层 +* 时组内一个量词即可触发(如 (a+)+),
|
||||
// 外层 ? 时需组内两个量词才触发(排除 (\d+)? 误报)
|
||||
if (/\([^)]*[+*?][^)]*\)[+*]/.test(pattern)) return true;
|
||||
if (/\([^)]*[+*?][^)]*[+*?][^)]*\)[?]/.test(pattern)) return true;
|
||||
|
||||
// 2. 重叠量词 — 补充 a+a+ 漏报
|
||||
if (/[+*][+*]/.test(pattern)) return true;
|
||||
// 审查修复: 补充 a+a+ / a+.*a+ 等重叠量词检测
|
||||
if (/\w[+*]\s*\w[+*]/.test(pattern)) return true;
|
||||
if (/\.\*[+*]\.\*[+*]/.test(pattern)) return true;
|
||||
|
||||
// 3. 交替分支加量词 — 放宽: 仅当分支有重叠前缀时才危险
|
||||
// 移除对 (GET|POST)+ 的误报,只检测真正危险的重叠分支
|
||||
// (a|a)* 类型难以用正则精确检测,保留简化版
|
||||
if (/\(([^)]+)\|(\1[^)]*)\)[+*?]/.test(pattern)) return true;
|
||||
if (/\(([^)]*\|[^)]*)\)[+*?]/.test(pattern) && /(.)\1.*\|.*\1/.test(pattern)) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
export class FileEditorTool implements IMetonaTool {
|
||||
readonly definition: MetonaToolDef = {
|
||||
name: 'file_editor',
|
||||
@@ -159,6 +196,11 @@ export class FileEditorTool implements IMetonaTool {
|
||||
if (pattern.length > 500) {
|
||||
return { success: false, error: 'Regex pattern too long (max 500 chars)' };
|
||||
}
|
||||
// #45 修复: ReDoS 防护 — 检测灾难性正则模式,拒绝可能导致指数级回溯的 pattern
|
||||
// 攻击场景:恶意 LLM 传入 (a+)+ 等模式,在长字符串上阻塞主进程
|
||||
if (isPotentiallyCatastrophicRegex(pattern)) {
|
||||
return { success: false, error: 'Potentially catastrophic regex pattern detected (ReDoS risk): nested or overlapping quantifiers' };
|
||||
}
|
||||
const startLine = Math.max(1, (args.start_line as number) ?? 1);
|
||||
const endLine = Math.min(lines.length, (args.end_line as number) ?? lines.length);
|
||||
if (endLine < startLine) {
|
||||
@@ -178,6 +220,15 @@ export class FileEditorTool implements IMetonaTool {
|
||||
if (multiline) {
|
||||
// F2-6: 跨行匹配 — 对整个目标内容做正则替换(支持多行代码块替换)
|
||||
const targetContent = lines.slice(startLine - 1, endLine).join('\n');
|
||||
// #45 修复: 限制 multiline 模式的目标内容长度,防止大文件上的 regex 执行导致主进程阻塞
|
||||
// Node.js RegExp 执行是同步的,超长内容 + 复杂正则可阻塞事件循环
|
||||
const MAX_REGEX_CONTENT_LENGTH = 100_000;
|
||||
if (targetContent.length > MAX_REGEX_CONTENT_LENGTH) {
|
||||
return {
|
||||
success: false,
|
||||
error: `Target content too large for multiline regex (${targetContent.length} chars, max ${MAX_REGEX_CONTENT_LENGTH}). Use a smaller line range or split the operation.`,
|
||||
};
|
||||
}
|
||||
const matches = targetContent.match(regex);
|
||||
if (matches) replaceCount = matches.length;
|
||||
const replacedContent = targetContent.replace(regex, replacement);
|
||||
|
||||
Reference in New Issue
Block a user