Two false positives in the local PreToolUse agent gate on CLI 0.10.0. Both share a shape: writing about a dangerous thing is treated as doing it, so security documentation, runbooks, and test fixtures become unwritable.
Related in spirit to the rule-narrowing work in #182 / #205 / #210, but a different subsystem — this is the local command/secret gate, not the remote SAST rules.
Environment: macOS 15 (darwin/arm64) · Node v26.0.0 · @rafter-security/cli 0.10.0 · betterleaks 1.1.2 · Claude Code integration.
1. Heredoc bodies are scanned as if they were executable
Quoted strings and grep arguments are handled correctly. Heredoc bodies are not:
tool_input.command |
decision |
echo "never run rm -rf / on prod" |
allow ✅ |
grep -r "rm -rf /" /var/log |
allow ✅ |
cat > a.md <<EOF … never run rm -rf / on prod … EOF |
deny ❌ |
cat > c.md <<EOF … fenced `rm -rf / --no-preserve-root` … EOF |
deny ❌ |
Reproduce:
printf '%s' '{"tool_name":"Bash","tool_input":{"command":"cat > /tmp/a.md <<EOF\nnever run rm -rf / on prod\nEOF"}}' \
| rafter hook pretool
Returns "permissionDecision":"deny" for a command whose only effect is writing a markdown file.
Impact: an agent cannot author an incident report, a runbook, a detection rule, or a test fixture that mentions a destructive command. I hit this writing up an unrelated bug report — cat > report.md <<'MD' was denied because the document quoted rm -rf / inside a fenced code block.
Suggested fix: exclude heredoc bodies from pattern matching, the same way quoted strings already are.
2. The regex secret engine lacks betterleaks' allowlist for documentation credentials
The bundled betterleaks correctly allowlists AWS's canonical documentation access key. Rafter's own regex engine does not — and that engine is the one wired into the blocking path:
$ printf 'key = AKIAIOSFODNN7EX*MPLE\n' | betterleaks stdin
INF no leaks found
Write tool, content "betterleaks allowlists AKIAIOSFODNN7EX*MPLE ..." -> deny
Write tool, same content with one character masked -> allow
(Substitute the real AWS documentation key for the * to reproduce. It is masked here because spelling it correctly makes this very issue body unwritable through an agent with the gate enabled — which is the bug.)
Impact: the two engines disagree, and the more naive one holds the veto. Security documentation, onboarding material, test fixtures, and bug reports citing well-known placeholder credentials cannot be written.
Suggested fix: share betterleaks' allowlist of known documentation/test credentials with the regex engine, and reserve the blocking path for matches in executable position.
Happy to test a patch on either.
Two false positives in the local
PreToolUseagent gate on CLI 0.10.0. Both share a shape: writing about a dangerous thing is treated as doing it, so security documentation, runbooks, and test fixtures become unwritable.Related in spirit to the rule-narrowing work in #182 / #205 / #210, but a different subsystem — this is the local command/secret gate, not the remote SAST rules.
Environment: macOS 15 (darwin/arm64) · Node v26.0.0 ·
@rafter-security/cli0.10.0 · betterleaks 1.1.2 · Claude Code integration.1. Heredoc bodies are scanned as if they were executable
Quoted strings and
greparguments are handled correctly. Heredoc bodies are not:tool_input.commandecho "never run rm -rf / on prod"grep -r "rm -rf /" /var/logcat > a.md <<EOF…never run rm -rf / on prod…EOFcat > c.md <<EOF… fenced`rm -rf / --no-preserve-root`…EOFReproduce:
Returns
"permissionDecision":"deny"for a command whose only effect is writing a markdown file.Impact: an agent cannot author an incident report, a runbook, a detection rule, or a test fixture that mentions a destructive command. I hit this writing up an unrelated bug report —
cat > report.md <<'MD'was denied because the document quotedrm -rf /inside a fenced code block.Suggested fix: exclude heredoc bodies from pattern matching, the same way quoted strings already are.
2. The regex secret engine lacks betterleaks' allowlist for documentation credentials
The bundled betterleaks correctly allowlists AWS's canonical documentation access key. Rafter's own regex engine does not — and that engine is the one wired into the blocking path:
(Substitute the real AWS documentation key for the
*to reproduce. It is masked here because spelling it correctly makes this very issue body unwritable through an agent with the gate enabled — which is the bug.)Impact: the two engines disagree, and the more naive one holds the veto. Security documentation, onboarding material, test fixtures, and bug reports citing well-known placeholder credentials cannot be written.
Suggested fix: share betterleaks' allowlist of known documentation/test credentials with the regex engine, and reserve the blocking path for matches in executable position.
Happy to test a patch on either.