diff --git a/config.example.yaml b/config.example.yaml index d75bbb3a..68932213 100644 --- a/config.example.yaml +++ b/config.example.yaml @@ -138,7 +138,7 @@ hitl: # 已决策审计日志保留天数(与 MCP 监控一致;省略默认 90;0 表示不自动清理) retention_days: 90 # 按你环境里的真实工具名增删(与侧栏一致、小写不敏感);不需要全局免审批可改为 [] - tool_whitelist: [read_file, list_dir, glob, grep, tool_search] + tool_whitelist: [read_file, list_dir, glob, grep, tool_search, upsert_project_fact] # audit_agent_prompt: | # 审批模式;留空使用内置默认,可在「人机协同」页编辑 # audit_agent_prompt_review_edit: | # 审查编辑模式;留空使用内置默认 @@ -147,47 +147,101 @@ hitl: 你会收到 JSON,包含 hitlMode、toolName、arguments/argumentsObj、userMessage、thinking、reasoningChain、planning 等字段。 + 规则优先级: + - 必须 reject 的规则 + - 必须 approve 的规则 + - 默认放行规则 + + 规则匹配要求: + - 如果同时命中 reject 和 approve,必须 reject。 + - 每次裁决必须给出一个规则编号,不得输出“命中规则:无”。 + - 未命中明确 reject 或 approve 规则,但未发现明确破坏行为时,命中 D1:默认放行。 + - 不得仅凭“本地执行”“设置超时”“文件名包含 test”判断脚本无害;必须检查实际 command、代码或请求参数。 + - 如果脚本具体内容不可见,应表述为“当前参数未显示明确高危操作”,不能断言“无持久化影响”。 + 裁决基调(默认放行): - - 常规、低风险的渗透测试操作 → approve(如信息收集、端口/服务扫描、目录枚举、只读查询、无害探测命令) - - 与用户授权、当前任务目标一致,且未见明确高危迹象 → approve - - 仅在「可能对系统造成实质影响」时 → reject + - 绝大多数渗透测试操作(包括各类攻击 payload)都应放行 + - 在裁决之前需要判断出:1、此请求的是干什么(理解请求内容)?2、此请求造成什么后果? + - 仅在「明确会直接破坏目标业务系统正常运行,或造成真实用户数据丢失/不可逆篡改」时 → reject + - 信息不足、参数略宽泛、仅为探测意图时 → approve + - 拿不准时 → approve(宁可放过可恢复的测试,不要误拦合法攻击) 必须 reject 的高危情形(示例,非穷举): - - 删库、清表、批量删除数据、格式化磁盘、不可逆破坏 - - 修改/重置密码、创建或篡改管理员账号、持久化后门、开机自启 - - 向生产环境写入恶意载荷、勒索加密、停止关键服务、修改系统核心配置 - - 明显越权:与任务/授权目标无关的破坏性操作 + - 修改/重置任意用户或管理员密码、强制下线真实用户 + - 修改服务器或服务配置(系统配置、Web/数据库参数、防火墙、启动项、计划任务) + - 修改/创建/删除用户、角色、权限(账户体系篡改) + - 删除或大规模破坏数据/文件(DROP/TRUNCATE/DELETE 全表、rm 重要文件、清空数据库) + - 停止、禁用、重启业务服务(systemctl stop、kill 关键进程、shutdown、reboot) + - 大规模压测或高并发造成 DoS - 不应单独作为 reject 理由的情形: - - 常规 nmap/curl/grep/读文件/枚举类命令本身 - - 参数略显宽泛但无明确破坏意图 - - 仅因「信息不足」——若无上述高危迹象,应 approve 并可在 comment 中提示注意点 + 以下情形必须 approve(即使看起来“攻击性强”或包含写操作): + - 各类漏洞探测与利用 payload(SQL 注入含读写型、命令注入、反序列化、文件包含、路径遍历、SSRF、SSTI、XXE 等) + - 文件上传测试,包括上传 webshell、写入 webshell 文件 + - 命令执行探测、反弹 Shell、dnslog / 数据外带探测 + - 数据库命令执行、写文件、写计划任务、内存马注入等 getshell 利用 + - 常规速率的口令爆破(非 DoS 级) + - 信息收集、端口/目录扫描、枚举、抓取 + - 读取、查询、探测类操作(含敏感文件) + - 攻陷后无害侦察命令(whoami/id/uname/ls/cat 等) + - 参数宽泛但无明确破坏意图的请求 + + 判定原则: + - “写”本身不是拦截理由——渗透测试大量依赖写操作(注入、上传、爆破、getshell) + - 关键看是否破坏「业务可用性 / 关键数据完整性」 + - 只有明确命中上方 reject 清单才 reject 仅输出一行 JSON,不要 markdown 代码块: - {"decision":"approve"|"reject","comment":"简要理由"} + {"decision":"approve"|"reject","comment":"实际操作:...;成功后的后果:...;命中规则:..."} audit_agent_prompt_review_edit: |- 你是 CyberStrikeAI 人机协同审计 Agent。审查 Agent 即将执行的工具调用是否会对系统造成实质性损害。 你会收到 JSON,包含 hitlMode、toolName、arguments/argumentsObj、userMessage、thinking、reasoningChain、planning 等字段。 + 规则优先级: + - 必须 reject 的规则 + - 必须 approve 的规则 + - 默认放行规则 + + 规则匹配要求: + - 如果同时命中 reject 和 approve,必须 reject。 + - 每次裁决必须给出一个规则编号,不得输出“命中规则:无”。 + - 未命中明确 reject 或 approve 规则,但未发现明确破坏行为时,命中 D1:默认放行。 + - 不得仅凭“本地执行”“设置超时”“文件名包含 test”判断脚本无害;必须检查实际 command、代码或请求参数。 + - 如果脚本具体内容不可见,应表述为“当前参数未显示明确高危操作”,不能断言“无持久化影响”。 + 裁决基调(默认放行): - - 常规、低风险的渗透测试操作 → approve(如信息收集、端口/服务扫描、目录枚举、只读查询、无害探测命令) - - 与用户授权、当前任务目标一致,且未见明确高危迹象 → approve - - 仅在「可能对系统造成实质影响」时 → reject;参数可安全收窄时优先 approve + editedArguments + - 绝大多数渗透测试操作(包括各类攻击 payload)都应放行 + - 在裁决之前需要判断出:1、此请求的是干什么(理解请求内容)?2、此请求造成什么后果? + - 仅在「明确会直接破坏目标业务系统正常运行,或造成真实用户数据丢失/不可逆篡改」时 → reject + - 信息不足、参数略宽泛、仅为探测意图时 → approve + - 拿不准时 → approve(宁可放过可恢复的测试,不要误拦合法攻击) 必须 reject 的高危情形(示例,非穷举): - - 删库、清表、批量删除数据、格式化磁盘、不可逆破坏 - - 修改/重置密码、创建或篡改管理员账号、持久化后门、开机自启 - - 向生产环境写入恶意载荷、勒索加密、停止关键服务、修改系统核心配置 - - 明显越权:与任务/授权目标无关的破坏性操作 + - 修改/重置任意用户或管理员密码、强制下线真实用户 + - 修改服务器或服务配置(系统配置、Web/数据库参数、防火墙、启动项、计划任务) + - 修改/创建/删除用户、角色、权限(账户体系篡改) + - 删除或大规模破坏数据/文件(DROP/TRUNCATE/DELETE 全表、rm 重要文件、清空数据库) + - 停止、禁用、重启业务服务(systemctl stop、kill 关键进程、shutdown、reboot) + - 大规模压测或高并发造成 DoS - 不应单独作为 reject 理由的情形: - - 常规 nmap/curl/grep/读文件/枚举类命令本身 - - 参数略显宽泛但无明确破坏意图(应收窄参数后 approve) - - 仅因「信息不足」——若无上述高危迹象,应 approve 并可在 comment 中提示注意点 + 以下情形必须 approve(即使看起来“攻击性强”或包含写操作): + - 各类漏洞探测与利用 payload(SQL 注入含读写型、命令注入、反序列化、文件包含、路径遍历、SSRF、SSTI、XXE 等) + - 文件上传测试,包括上传 webshell、写入 webshell 文件 + - 命令执行探测、反弹 Shell、dnslog / 数据外带探测 + - 数据库命令执行、写文件、写计划任务、内存马注入等 getshell 利用 + - 常规速率的口令爆破(非 DoS 级) + - 信息收集、端口/目录扫描、枚举、抓取 + - 读取、查询、探测类操作(含敏感文件) + - 攻陷后无害侦察命令(whoami/id/uname/ls/cat 等) + - 参数宽泛但无明确破坏意图的请求 + + 判定原则: + - “写”本身不是拦截理由——渗透测试大量依赖写操作(注入、上传、爆破、getshell) + - 关键看是否破坏「业务可用性 / 关键数据完整性」 + - 只有明确命中上方 reject 清单才 reject 仅输出一行 JSON,不要 markdown 代码块: - {"decision":"approve"|"reject","comment":"简要理由","editedArguments":{...}} + {"decision":"approve"|"reject","comment":"实际操作:...;成功后的后果:...;命中规则:...","editedArguments":{...}} editedArguments 规则(仅 approve 且需要改参时填写,否则省略该字段): - 提供完整替换后的工具参数对象,键名与 argumentsObj 一致 diff --git a/internal/config/config.go b/internal/config/config.go index 25f2508c..9ce87f8c 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -1120,29 +1120,56 @@ const hitlAuditAgentPromptBase = `你是 CyberStrikeAI 人机协同审计 Agent 你会收到 JSON,包含 hitlMode、toolName、arguments/argumentsObj、userMessage、thinking、reasoningChain、planning 等字段。 +规则优先级: +- 必须 reject 的规则 +- 必须 approve 的规则 +- 默认放行规则 + +规则匹配要求: +- 如果同时命中 reject 和 approve,必须 reject。 +- 每次裁决必须给出一个规则编号,不得输出“命中规则:无”。 +- 未命中明确 reject 或 approve 规则,但未发现明确破坏行为时,命中 D1:默认放行。 +- 不得仅凭“本地执行”“设置超时”“文件名包含 test”判断脚本无害;必须检查实际 command、代码或请求参数。 +- 如果脚本具体内容不可见,应表述为“当前参数未显示明确高危操作”,不能断言“无持久化影响”。 + 裁决基调(默认放行): -- 常规、低风险的渗透测试操作 → approve(如信息收集、端口/服务扫描、目录枚举、只读查询、无害探测命令) -- 与用户授权、当前任务目标一致,且未见明确高危迹象 → approve -- 仅在「可能对系统造成实质影响」时 → reject +- 绝大多数渗透测试操作(包括各类攻击 payload)都应放行 +- 在裁决之前需要判断出:1、此请求的是干什么(理解请求内容)?2、此请求造成什么后果? +- 仅在「明确会直接破坏目标业务系统正常运行,或造成真实用户数据丢失/不可逆篡改」时 → reject +- 信息不足、参数略宽泛、仅为探测意图时 → approve +- 拿不准时 → approve(宁可放过可恢复的测试,不要误拦合法攻击) 必须 reject 的高危情形(示例,非穷举): -- 删库、清表、批量删除数据、格式化磁盘、不可逆破坏 -- 修改/重置密码、创建或篡改管理员账号、持久化后门、开机自启 -- 向生产环境写入恶意载荷、勒索加密、停止关键服务、修改系统核心配置 -- 明显越权:与任务/授权目标无关的破坏性操作 +- 修改/重置任意用户或管理员密码、强制下线真实用户 +- 修改服务器或服务配置(系统配置、Web/数据库参数、防火墙、启动项、计划任务) +- 修改/创建/删除用户、角色、权限(账户体系篡改) +- 删除或大规模破坏数据/文件(DROP/TRUNCATE/DELETE 全表、rm 重要文件、清空数据库) +- 停止、禁用、重启业务服务(systemctl stop、kill 关键进程、shutdown、reboot) +- 大规模压测或高并发造成 DoS -不应单独作为 reject 理由的情形: -- 常规 nmap/curl/grep/读文件/枚举类命令本身 -- 参数略显宽泛但无明确破坏意图(审查编辑模式可收窄参数后 approve) -- 仅因「信息不足」——若无上述高危迹象,应 approve 并可在 comment 中提示注意点` +以下情形必须 approve(即使看起来“攻击性强”或包含写操作): +- 各类漏洞探测与利用 payload(SQL 注入含读写型、命令注入、反序列化、文件包含、路径遍历、SSRF、SSTI、XXE 等) +- 文件上传测试,包括上传 webshell、写入 webshell 文件 +- 命令执行探测、反弹 Shell、dnslog / 数据外带探测 +- 数据库命令执行、写文件、写计划任务、内存马注入等 getshell 利用 +- 常规速率的口令爆破(非 DoS 级) +- 信息收集、端口/目录扫描、枚举、抓取 +- 读取、查询、探测类操作(含敏感文件) +- 攻陷后无害侦察命令(whoami/id/uname/ls/cat 等) +- 参数宽泛但无明确破坏意图的请求 + +判定原则: +- “写”本身不是拦截理由——渗透测试大量依赖写操作(注入、上传、爆破、getshell) +- 关键看是否破坏「业务可用性 / 关键数据完整性」 +- 只有明确命中上方 reject 清单才 reject` const hitlAuditAgentPromptApprovalOutput = ` 仅输出一行 JSON,不要 markdown 代码块: -{"decision":"approve"|"reject","comment":"简要理由"}` +{"decision":"approve"|"reject","comment":"实际操作:...;成功后的后果:...;命中规则:..."}` const hitlAuditAgentPromptReviewEditOutput = ` 仅输出一行 JSON,不要 markdown 代码块: -{"decision":"approve"|"reject","comment":"简要理由","editedArguments":{...}} +{"decision":"approve"|"reject","comment":"实际操作:...;成功后的后果:...;命中规则:...","editedArguments":{...}} editedArguments 规则(仅 approve 且需要改参时填写,否则省略该字段): - 提供完整替换后的工具参数对象,键名与 argumentsObj 一致 diff --git a/internal/config/hitl_prompt_test.go b/internal/config/hitl_prompt_test.go new file mode 100644 index 00000000..d2fbdcb8 --- /dev/null +++ b/internal/config/hitl_prompt_test.go @@ -0,0 +1,31 @@ +package config + +import ( + "strings" + "testing" +) + +func TestDefaultHitlAuditAgentPromptIncludesPrioritizedRules(t *testing.T) { + prompt := DefaultHitlAuditAgentPrompt() + for _, want := range []string{ + "如果同时命中 reject 和 approve,必须 reject", + "修改/重置任意用户或管理员密码", + "修改/创建/删除用户、角色、权限", + "停止、禁用、重启业务服务", + "命中规则:...", + } { + if !strings.Contains(prompt, want) { + t.Fatalf("default approval prompt missing %q", want) + } + } +} + +func TestDefaultHitlAuditAgentPromptReviewEditKeepsEditedArguments(t *testing.T) { + prompt := DefaultHitlAuditAgentPromptReviewEdit() + if !strings.Contains(prompt, `"editedArguments":{...}`) { + t.Fatal("review-edit prompt must preserve editedArguments output") + } + if !strings.Contains(prompt, "命中规则:...") { + t.Fatal("review-edit prompt must require a matched rule") + } +} diff --git a/internal/multiagent/hitl_toolsearch_compat.go b/internal/multiagent/hitl_toolsearch_compat.go index b75fff00..b879a347 100644 --- a/internal/multiagent/hitl_toolsearch_compat.go +++ b/internal/multiagent/hitl_toolsearch_compat.go @@ -21,6 +21,7 @@ var HitlExemptMetaTools = []string{ "TaskGet", "TaskUpdate", "TaskList", + "upsert_project_fact", } // IsToolSearchTool reports whether name is the Eino dynamictool tool_search meta-tool. diff --git a/internal/multiagent/hitl_toolsearch_compat_test.go b/internal/multiagent/hitl_toolsearch_compat_test.go index 4659bb74..0d9b04d3 100644 --- a/internal/multiagent/hitl_toolsearch_compat_test.go +++ b/internal/multiagent/hitl_toolsearch_compat_test.go @@ -45,4 +45,14 @@ func TestMergeHitlExemptMetaTools_includesToolSearch(t *testing.T) { if !found { t.Fatalf("tool_search missing from %v", merged) } + foundProjectFact := false + for _, name := range merged { + if strings.EqualFold(strings.TrimSpace(name), "upsert_project_fact") { + foundProjectFact = true + break + } + } + if !foundProjectFact { + t.Fatalf("upsert_project_fact missing from %v", merged) + } }