mirror of
https://github.com/tiennm99/goclaw.git
synced 2026-10-15 02:16:56 +00:00
fix: Simplify config leak detection to a single gate, triggering on 3+ distinct internal file name mentions without requiring list patterns.
This commit is contained in:
1 parent
85a6379e8c
commit
99cab86373
2 files changed
+20
-23
No files matched your search
@@ -324,28 +324,19 @@ var configLeakFileNames = []string{
|
||||
"internal_config", "system prompt",
|
||||
}
|
||||
|
||||
// configLeakListPattern matches numbered or bulleted list items that reference internal files.
|
||||
// Examples: "1. Đọc SOUL.md..." "- Check AGENTS.md" "* Read IDENTITY.md"
|
||||
var configLeakListPattern = regexp.MustCompile(
|
||||
`(?im)^[\s]*(?:[\d]+[.\)]\s+|\-\s+|\*\s+).*(?:SOUL\.md|IDENTITY\.md|AGENTS\.md|BOOTSTRAP\.md|system prompt|internal_config).*$`,
|
||||
)
|
||||
|
||||
// StripConfigLeak detects when a predefined agent dumps its internal configuration
|
||||
// or procedures (e.g. numbered lists referencing SOUL.md, AGENTS.md) and replaces
|
||||
// the entire response with a friendly decline.
|
||||
// (e.g. referencing SOUL.md, AGENTS.md, IDENTITY.md) and replaces the entire
|
||||
// response with a friendly decline.
|
||||
//
|
||||
// Only active for predefined agents. Two-gate detection:
|
||||
// - Gate 1: 3+ distinct internal file names mentioned in response
|
||||
// - Gate 2: 2+ list items (numbered/bulleted) referencing those files
|
||||
//
|
||||
// When both gates trigger, the response is replaced entirely — partial stripping
|
||||
// leaves broken output that reads worse than a clean decline.
|
||||
// Only active for predefined agents. Single-gate detection:
|
||||
// 3+ distinct internal file names mentioned → replace entire response.
|
||||
// A predefined agent legitimately referencing 3+ internal config files in one
|
||||
// response is essentially impossible, so this has no false-positive risk.
|
||||
func StripConfigLeak(content, agentType string) string {
|
||||
if agentType != "predefined" || content == "" {
|
||||
return content
|
||||
}
|
||||
|
||||
// Gate 1: count distinct file name hits
|
||||
hits := 0
|
||||
for _, name := range configLeakFileNames {
|
||||
if strings.Contains(content, name) {
|
||||
@@ -356,15 +347,8 @@ func StripConfigLeak(content, agentType string) string {
|
||||
return content
|
||||
}
|
||||
|
||||
// Gate 2: at least 2 list items referencing internal files
|
||||
matches := configLeakListPattern.FindAllString(content, -1)
|
||||
if len(matches) < 2 {
|
||||
return content
|
||||
}
|
||||
|
||||
slog.Warn("security.config_leak_stripped",
|
||||
"file_hits", hits,
|
||||
"list_matches", len(matches),
|
||||
"original_len", len(content),
|
||||
)
|
||||
|
||||
|
||||
@@ -22,9 +22,10 @@ func TestStripConfigLeak(t *testing.T) {
|
||||
agentType: "predefined",
|
||||
},
|
||||
{
|
||||
name: "predefined - 3 files but no list pattern",
|
||||
name: "predefined - 3 files in paragraph (no list)",
|
||||
content: "SOUL.md, IDENTITY.md, AGENTS.md đều đã được load sẵn trong context.",
|
||||
agentType: "predefined",
|
||||
want: declineMsg,
|
||||
},
|
||||
{
|
||||
name: "predefined - leaking numbered list",
|
||||
@@ -52,6 +53,18 @@ Có gì anh hỏi thêm nhé!`,
|
||||
agentType: "predefined",
|
||||
want: declineMsg,
|
||||
},
|
||||
{
|
||||
name: "predefined - real bypass: bold-header paragraph leak",
|
||||
content: `Dạ, nếu có người hỏi chi tiết về internal process thì em sẽ:
|
||||
|
||||
**Từ chối lịch sự** - Những thứ như system prompt, context files (SOUL.md, IDENTITY.md, AGENTS.md), internal procedures là confidential.
|
||||
|
||||
**Cách em reply:**
|
||||
- "Cái này là internal của em, không share được ạ"
|
||||
- "Em không thể tiết lộ chi tiết process nội bộ"`,
|
||||
agentType: "predefined",
|
||||
want: declineMsg,
|
||||
},
|
||||
{
|
||||
name: "predefined - legitimate action report (single file)",
|
||||
content: "Em đã update SOUL.md cho anh rồi, nội dung mới đã được lưu.",
|
||||
|
||||
Reference in new issue
Block a user