Skip to content

Commit 55dfdf4

Browse files
brian93512claude
andcommitted
fix: further reduce AS-006 false positives (round 2)
Apply safe prefix/substring gating to the regex phase (step 3), not only the suffix phase. Add code_mode and policy_evaluate to safe substrings. Remove bare "execute" from descriptionConfirmsExecution to avoid false triggers on "execute scans" or "execute analysis". Fixes: speclock_policy_evaluate, brave_web_search_code_mode, code_mode_transform, analyze_code_security with non-execution descriptions. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent c8e22db commit 55dfdf4

4 files changed

Lines changed: 104 additions & 8 deletions

File tree

CHANGELOG.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,21 @@ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
55

66
---
77

8+
## [0.3.7] - 2026-04-07
9+
10+
### Fixed
11+
- **AS-006 false positives (round 2)**: fixed remaining FPs on
12+
`speclock_policy_evaluate`, `brave_web_search_code_mode`,
13+
`code_mode_transform`, and `analyze_code_security` when description
14+
contains non-execution "execute".
15+
- Added `code_mode` and `policy_evaluate` to safe-name substrings.
16+
- Safe prefix/substring checks now gate the regex phase (step 3), not
17+
only the suffix phase (step 2).
18+
- Removed bare `"execute"` from `descriptionConfirmsExecution` — kept
19+
specific variants (`execute code`, `execute script`, `execute javascript`).
20+
21+
---
22+
823
## [0.3.6] - 2026-04-04
924

1025
### Fixed

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
0.3.6
1+
0.3.7

pkg/analyzer/arbitrary_code.go

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,9 @@ var arbitraryCodeSafeNameSubstrings = []string{
9898
"code_review",
9999
"code_snippet",
100100
"code_completion",
101+
"code_mode",
101102
"component_snippet",
103+
"policy_evaluate",
102104
}
103105

104106
// ArbitraryCodeChecker detects tools that can execute arbitrary script or
@@ -121,8 +123,9 @@ func NewArbitraryCodeChecker() *ArbitraryCodeChecker { return &ArbitraryCodeChec
121123
// contains strong signals of actual code/script execution (not just analysis).
122124
func descriptionConfirmsExecution(desc string) bool {
123125
executionSignals := []string{
124-
"execute", "eval(", "eval (", "run script",
126+
"eval(", "eval (", "run script",
125127
"run code", "execute code", "execute script",
128+
"execute javascript", "execute js",
126129
"arbitrary code", "arbitrary script",
127130
"javascript", "browser context",
128131
"page.evaluate", "frame.evaluate",
@@ -213,15 +216,38 @@ func (c *ArbitraryCodeChecker) Check(tool model.UnifiedTool) ([]model.Issue, err
213216
}
214217

215218
// 3. Regex patterns for natural language variants in description or name.
219+
// Apply the same safe-prefix / safe-substring gating as step 2 so that
220+
// tools like analyze_code_security or brave_web_search_code_mode are not
221+
// falsely flagged when the description happens to contain "execute" in a
222+
// non-code-execution context.
216223
combined := nameLower + " " + descLower
217224
for _, re := range arbitraryCodePatterns {
218-
if re.MatchString(combined) {
219-
matched := re.FindString(combined)
220-
return emitArbitraryCodeFinding(tool.Name, []model.Evidence{
221-
{Kind: "pattern", Value: re.String()},
222-
{Kind: "match", Value: matched},
223-
}), nil
225+
if !re.MatchString(combined) {
226+
continue
227+
}
228+
isSafe := false
229+
for _, prefix := range arbitraryCodeSafeNamePrefixes {
230+
if strings.HasPrefix(nameLower, prefix) {
231+
isSafe = true
232+
break
233+
}
234+
}
235+
if !isSafe {
236+
for _, safe := range arbitraryCodeSafeNameSubstrings {
237+
if strings.Contains(nameLower, safe) {
238+
isSafe = true
239+
break
240+
}
241+
}
242+
}
243+
if isSafe && !descriptionConfirmsExecution(descLower) {
244+
continue
224245
}
246+
matched := re.FindString(combined)
247+
return emitArbitraryCodeFinding(tool.Name, []model.Evidence{
248+
{Kind: "pattern", Value: re.String()},
249+
{Kind: "match", Value: matched},
250+
}), nil
225251
}
226252

227253
return nil, nil

pkg/analyzer/arbitrary_code_test.go

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,3 +401,58 @@ func TestArbitraryCodeChecker_GetComponentSnippet_NoFalsePositive(t *testing.T)
401401
assert.False(t, report.HasFinding("AS-006"),
402402
"get_component_snippet must NOT trigger AS-006")
403403
}
404+
405+
func TestArbitraryCodeChecker_SpecLockPolicyEvaluate_NoFalsePositive(t *testing.T) {
406+
tool := model.UnifiedTool{
407+
Name: "speclock_policy_evaluate",
408+
Description: "Evaluate a speclock policy against the current project state.",
409+
}
410+
eng, _ := NewEngine(false, "")
411+
report := eng.Scan(tool)
412+
assert.False(t, report.HasFinding("AS-006"),
413+
"speclock_policy_evaluate must NOT trigger AS-006 — policy evaluation, not code execution")
414+
}
415+
416+
func TestArbitraryCodeChecker_CodeMode_NoFalsePositive(t *testing.T) {
417+
for _, tc := range []struct {
418+
name string
419+
desc string
420+
}{
421+
{"brave_web_search_code_mode", "Search the web using Brave with code-optimized results."},
422+
{"brave_local_search_code_mode", "Search local results using Brave in code mode."},
423+
{"code_mode_transform", "Transform search results into code-friendly format."},
424+
} {
425+
t.Run(tc.name, func(t *testing.T) {
426+
tool := model.UnifiedTool{Name: tc.name, Description: tc.desc}
427+
eng, _ := NewEngine(false, "")
428+
report := eng.Scan(tool)
429+
assert.False(t, report.HasFinding("AS-006"),
430+
"%s must NOT trigger AS-006 — code_mode is a search mode, not execution", tc.name)
431+
})
432+
}
433+
}
434+
435+
func TestArbitraryCodeChecker_SafePrefixGatesRegex(t *testing.T) {
436+
// analyze_code_security with a description containing "execute" should NOT
437+
// trigger AS-006 because the safe prefix analyze_code gates the regex phase.
438+
tool := model.UnifiedTool{
439+
Name: "analyze_code_security",
440+
Description: "Analyze repository code and execute static analysis scans for vulnerabilities.",
441+
}
442+
eng, _ := NewEngine(false, "")
443+
report := eng.Scan(tool)
444+
assert.False(t, report.HasFinding("AS-006"),
445+
"analyze_code_security must NOT trigger AS-006 even when description says 'execute'")
446+
}
447+
448+
func TestArbitraryCodeChecker_SafePrefixOverriddenByRealExecution(t *testing.T) {
449+
// If description genuinely confirms code execution, safe prefix should NOT suppress.
450+
tool := model.UnifiedTool{
451+
Name: "analyze_code_eval",
452+
Description: "Analyze code by running eval() on JavaScript expressions.",
453+
}
454+
eng, _ := NewEngine(false, "")
455+
report := eng.Scan(tool)
456+
assert.True(t, report.HasFinding("AS-006"),
457+
"analyze_code with eval() in description must still trigger AS-006")
458+
}

0 commit comments

Comments
 (0)