diff --git a/backend/app/services/agent/agents/analysis.py b/backend/app/services/agent/agents/analysis.py index a7eaa5f..1933ae3 100644 --- a/backend/app/services/agent/agents/analysis.py +++ b/backend/app/services/agent/agents/analysis.py @@ -211,6 +211,31 @@ Action Input: {"target_path": ".", "rules": "auto"} 3. **上下文分析** - 看到可疑代码要读取上下文,理解完整逻辑 4. **自主判断** - 不要机械相信工具输出,要用你的专业知识判断 +## 🚨 知识工具使用警告(防止幻觉!) + +**知识库中的代码示例仅供概念参考,不是实际代码!** + +当你使用 `get_vulnerability_knowledge` 或 `query_security_knowledge` 时: +1. **知识示例 ≠ 项目代码** - 知识库的代码示例是通用示例,不是目标项目的代码 +2. **语言可能不匹配** - 知识库可能返回 Python 示例,但项目可能是 PHP/Rust/Go +3. **必须在实际代码中验证** - 你只能报告你在 read_file 中**实际看到**的漏洞 +4. **禁止推测** - 不要因为知识库说"这种模式常见"就假设项目中存在 + +❌ 错误做法(幻觉来源): +``` +1. 查询 auth_bypass 知识 -> 看到 JWT 示例 +2. 没有在项目中找到 JWT 代码 +3. 仍然报告 "JWT 认证绕过漏洞" <- 这是幻觉! +``` + +✅ 正确做法: +``` +1. 查询 auth_bypass 知识 -> 了解认证绕过的概念 +2. 使用 read_file 读取项目的认证代码 +3. 只有**实际看到**有问题的代码才报告漏洞 +4. file_path 必须是你**实际读取过**的文件 +``` + ## ⚠️ 关键约束 - 必须遵守! 1. **禁止直接输出 Final Answer** - 你必须先调用工具来分析代码 2. **至少调用两个工具** - 使用 smart_scan/semgrep_scan 进行扫描,然后用 read_file 查看代码 diff --git a/backend/app/services/agent/agents/recon.py b/backend/app/services/agent/agents/recon.py index 1244afa..1f0a53b 100644 --- a/backend/app/services/agent/agents/recon.py +++ b/backend/app/services/agent/agents/recon.py @@ -154,6 +154,35 @@ Final Answer: { - `line_start`: 行号 - `description`: 详细描述 +## 🚨 防止幻觉(关键!) + +**只报告你实际读取过的文件!** + +1. **file_path 必须来自实际工具调用结果** + - 只使用 list_files 返回的文件列表中的路径 + - 只使用 read_file 成功读取的文件路径 + - 不要"猜测"典型的项目结构(如 app.py, config.py) + +2. **行号必须来自实际代码** + - 只使用 read_file 返回内容中的真实行号 + - 不要编造行号 + +3. **禁止套用模板** + - 不要因为是 "Python 项目" 就假设存在 requirements.txt + - 不要因为是 "Web 项目" 就假设存在 routes.py 或 views.py + +❌ 错误做法: +``` +list_files 返回: ["main.rs", "lib.rs", "Cargo.toml"] +high_risk_areas: ["app.py:36 - 存在安全问题"] <- 这是幻觉!项目根本没有 app.py +``` + +✅ 正确做法: +``` +list_files 返回: ["main.rs", "lib.rs", "Cargo.toml"] +high_risk_areas: ["main.rs:xx - 可能存在问题"] <- 必须使用实际存在的文件 +``` + ## ⚠️ 关键约束 - 必须遵守! 1. **禁止直接输出 Final Answer** - 你必须先调用工具来收集项目信息 2. **至少调用三个工具** - 使用 rag_query 语义搜索关键入口,read_file 读取文件,list_files 仅查看根目录 diff --git a/backend/app/services/agent/agents/verification.py b/backend/app/services/agent/agents/verification.py index 9bab09e..cd6eed4 100644 --- a/backend/app/services/agent/agents/verification.py +++ b/backend/app/services/agent/agents/verification.py @@ -282,6 +282,33 @@ Action Input: {"file_path": "search.php"} - **uncertain**: 需要更多信息才能判断 - **false_positive**: 确认是误报,有明确理由 +## 🚨 防止幻觉验证(关键!) + +**Analysis Agent 可能报告不存在的文件!** 你必须验证: + +1. **文件必须存在** - 使用 read_file 读取发现中指定的文件 + - 如果 read_file 返回"文件不存在",该发现是 **false_positive** + - 不要尝试"猜测"正确的文件路径 + +2. **代码必须匹配** - 发现中的 code_snippet 必须在文件中真实存在 + - 如果文件内容与描述不符,该发现是 **false_positive** + +3. **不要"填补"缺失信息** - 如果发现缺少关键信息(如文件路径为空),标记为 uncertain + +❌ 错误做法: +``` +发现: "SQL注入在 api/database.py:45" +read_file 返回: "文件不存在" +判定: confirmed <- 这是错误的! +``` + +✅ 正确做法: +``` +发现: "SQL注入在 api/database.py:45" +read_file 返回: "文件不存在" +判定: false_positive,理由: "文件 api/database.py 不存在" +``` + ## ⚠️ 关键约束 1. **必须先调用工具验证** - 不允许仅凭已知信息直接判断 2. **优先使用 run_code** - 编写 Harness 进行动态验证 diff --git a/backend/app/services/agent/knowledge/tools.py b/backend/app/services/agent/knowledge/tools.py index 0b6c667..61d2787 100644 --- a/backend/app/services/agent/knowledge/tools.py +++ b/backend/app/services/agent/knowledge/tools.py @@ -126,6 +126,10 @@ class VulnerabilityKnowledgeInput(BaseModel): ..., description="漏洞类型,如: sql_injection, xss, command_injection, path_traversal, ssrf, deserialization, hardcoded_secrets, auth_bypass" ) + project_language: Optional[str] = Field( + None, + description="目标项目的主要编程语言(如 python, php, javascript, rust, go),用于过滤相关示例" + ) class GetVulnerabilityKnowledgeTool(AgentTool): @@ -165,13 +169,13 @@ class GetVulnerabilityKnowledgeTool(AgentTool): def args_schema(self) -> Type[BaseModel]: return VulnerabilityKnowledgeInput - async def _execute(self, vulnerability_type: str) -> ToolResult: + async def _execute(self, vulnerability_type: str, project_language: Optional[str] = None) -> ToolResult: """获取漏洞知识""" try: knowledge = await security_knowledge_rag.get_vulnerability_knowledge( vulnerability_type ) - + if not knowledge: available = security_knowledge_rag.get_all_vulnerability_types() return ToolResult( @@ -179,27 +183,55 @@ class GetVulnerabilityKnowledgeTool(AgentTool): data=f"未找到漏洞类型 '{vulnerability_type}' 的知识。\n\n可用的漏洞类型: {', '.join(available)}", metadata={"available_types": available}, ) - + # 格式化输出 output_parts = [ f"# {knowledge.get('title', vulnerability_type)}", f"严重程度: {knowledge.get('severity', 'N/A')}", ] - + if knowledge.get("cwe_ids"): output_parts.append(f"CWE: {', '.join(knowledge['cwe_ids'])}") if knowledge.get("owasp_ids"): output_parts.append(f"OWASP: {', '.join(knowledge['owasp_ids'])}") - + + # 🔥 v2.2: 添加语言不匹配警告 + content = knowledge.get("content", "") + knowledge_lang = self._detect_code_language(content) + + if project_language and knowledge_lang: + project_lang_lower = project_language.lower() + if knowledge_lang.lower() != project_lang_lower: + output_parts.append("") + output_parts.append("=" * 60) + output_parts.append(f"⚠️ **重要警告**: 以下示例代码是 {knowledge_lang.upper()} 语言") + output_parts.append(f" 你正在审计的项目是 {project_language.upper()} 项目") + output_parts.append(" **这些代码示例仅供概念参考,不要直接套用到目标项目!**") + output_parts.append(" 请在目标项目中查找该语言特有的等效漏洞模式。") + output_parts.append("=" * 60) + output_parts.append("") - output_parts.append(knowledge.get("content", "")) - + output_parts.append(content) + + # 🔥 v2.2: 添加使用指南 + output_parts.append("") + output_parts.append("---") + output_parts.append("📌 **使用指南**:") + output_parts.append("1. 以上知识仅供参考,你必须在实际代码中验证漏洞是否存在") + output_parts.append("2. 不要假设项目中存在示例中的代码模式") + output_parts.append("3. 只有在 read_file 读取到的代码中确实存在问题时才报告漏洞") + output_parts.append("4. 如果示例语言与项目语言不同,请查找该语言的等效漏洞模式") + return ToolResult( success=True, data="\n".join(output_parts), - metadata=knowledge, + metadata={ + **knowledge, + "knowledge_language": knowledge_lang, + "project_language": project_language, + }, ) - + except Exception as e: logger.error(f"Get vulnerability knowledge failed: {e}") return ToolResult( @@ -207,6 +239,35 @@ class GetVulnerabilityKnowledgeTool(AgentTool): error=f"获取漏洞知识失败: {str(e)}", ) + def _detect_code_language(self, content: str) -> Optional[str]: + """检测知识内容中的主要代码语言""" + # 检测代码块中的语言标记 + import re + code_blocks = re.findall(r'```(\w+)', content) + if code_blocks: + # 统计最常见的语言 + from collections import Counter + lang_counts = Counter(code_blocks) + most_common = lang_counts.most_common(1) + if most_common: + return most_common[0][0] + + # 基于内容特征检测 + if "def " in content or "import " in content or "@app.route" in content: + return "python" + if "