0
Fork 0
mirror of https://github.com/trailofbits/skills.git synced 2026-09-27 09:29:06 +00:00

gh-cli: intercept-github-curl.sh denies commands whose heredoc body mentions curl + a GitHub URL #333

Open
opened 2026-09-24 20:53:19 +00:00 by jeanmichelaudet · 0 comments
jeanmichelaudet commented 2026-09-24 20:53:19 +00:00 (Migrated from github.com)

Plugin: gh-cli 1.6.2, hooks/intercept-github-curl.sh (PreToolUse, matcher Bash)

What happens

The hook runs its two regexes over the whole tool_input.command string. When a command writes a file through a heredoc, and the file content contains curl followed by a GitHub URL, the command gets denied even though it never runs curl.

Minimal repro, as the command Claude Code sends to the Bash tool:

cat > .github/workflows/scan.yml <<'EOF'
      - run: curl -sSfL https://github.com/aquasecurity/trivy/releases/download/v0.50.0/trivy.tar.gz | tar xz
EOF

Result: permissionDecision: deny with Use gh release download --repo aquasecurity/trivy instead. The command only writes a YAML file. The curl runs later, on a CI runner that has no authenticated gh.

The same happens for a commit message that mentions one:
git commit -m 'docs: replace curl https://api.github.com/repos/o/r with gh api' is denied.
(A single-quoted 'curl ... that starts right after the quote passes, because the anchor requires whitespace before curl.)

Why it matters

The deny message names neither the plugin nor the script. Tracking it down took a grep under ~/.claude/plugins/cache/.

Possible fix

Before matching, drop heredoc bodies and quoted strings, the same way (^|[[:space:];|&])(curl|wget)[[:space:]] already tries to anchor on a command position. A minimal version strips everything after the first << delimiter up to the matching terminator. A fuller version checks only the command word of each ;/&&/||/| segment. The deny reason could also start with gh-cli plugin: so a user can find the source.

Happy to test a patch against the case above.

**Plugin:** `gh-cli` 1.6.2, `hooks/intercept-github-curl.sh` (PreToolUse, matcher `Bash`) ### What happens The hook runs its two regexes over the whole `tool_input.command` string. When a command writes a file through a heredoc, and the file content contains `curl` followed by a GitHub URL, the command gets denied even though it never runs curl. Minimal repro, as the command Claude Code sends to the Bash tool: ```bash cat > .github/workflows/scan.yml <<'EOF' - run: curl -sSfL https://github.com/aquasecurity/trivy/releases/download/v0.50.0/trivy.tar.gz | tar xz EOF ``` Result: `permissionDecision: deny` with `Use gh release download --repo aquasecurity/trivy instead`. The command only writes a YAML file. The curl runs later, on a CI runner that has no authenticated `gh`. The same happens for a commit message that mentions one: `git commit -m 'docs: replace curl https://api.github.com/repos/o/r with gh api'` is denied. (A single-quoted `'curl ...` that starts right after the quote passes, because the anchor requires whitespace before `curl`.) ### Why it matters The deny message names neither the plugin nor the script. Tracking it down took a grep under `~/.claude/plugins/cache/`. ### Possible fix Before matching, drop heredoc bodies and quoted strings, the same way `(^|[[:space:];|&])(curl|wget)[[:space:]]` already tries to anchor on a command position. A minimal version strips everything after the first `<<` delimiter up to the matching terminator. A fuller version checks only the command word of each `;`/`&&`/`||`/`|` segment. The deny reason could also start with `gh-cli plugin:` so a user can find the source. Happy to test a patch against the case above.
Sign in to join this conversation.
No milestone
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
skills/trailofbits-skills#333
No description provided.