Unverified 提交 69c0259b authored 作者: Will Chen's avatar Will Chen 提交者: GitHub

Allow markdown code spans in gh permission hook (#2309)

## Summary - Fixes false positive in gh permission hook when PR bodies contain markdown code spans like `concurrency` - Adds `MARKDOWN_CODE_SPAN_PATTERN` to neutralize backtick pairs with identifier-like content before checking for shell injection - Security preserved: actual command substitution patterns with spaces/special chars still blocked ## Test plan - [x] Tested commands with markdown code spans now pass - [x] Tested commands with actual command substitution patterns are still blocked - [x] Tested command chaining attempts are still blocked #skip-bugbot 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- This is an auto-generated description by cubic. --> --- ## Summary by cubic Allows safe markdown code spans inside double-quoted PR/issue bodies by neutralizing backtick-wrapped identifiers; command substitution and unsafe chaining remain blocked. - **Bug Fixes** - Neutralize identifier-like code spans only inside double quotes using MARKDOWN_CODE_SPAN_PATTERN; requires a dot, hyphen, or underscore and excludes plain words; still blocks backticks with spaces, args, or pipes. <sup>Written for commit 9d81ffe0bf0c58dd7862ffc16b49318698c8fb5d. Summary will update on new commits.</sup> <!-- End of auto-generated description by cubic. --> Co-authored-by: 's avatarClaude Opus 4.5 <noreply@anthropic.com>
上级 04239c1c
......@@ -58,6 +58,12 @@ BLOCKED (denied):
- Command substitution: $() ``
- Process substitution: <() >()
- Piping to non-safe commands
Note: Markdown code spans with identifier-like content are allowed in double-quoted
strings (common in PR/issue descriptions). Code spans must contain at least one
dot, hyphen, or underscore to be recognized as identifiers (e.g., `config.json`,
`my-component`, `my_variable`). Plain words like `word` are NOT allowed as they
could be actual commands like `env` or `whoami`.
"""
import json
import sys
......@@ -108,6 +114,16 @@ SINGLE_QUOTED_PATTERN = re.compile(r"'[^']*'")
# We use this to allow patterns like: grep -E "bug|error"
SAFE_DOUBLE_QUOTED_PATTERN = re.compile(r'"[^"$`]*"')
# Pattern to match markdown-style inline code spans that look like identifiers
# Must contain at least one of: dot, hyphen, or underscore to distinguish from commands
# Matches: `config.json`, `my-component`, `my_variable`, `package.json`
# Does NOT match: `whoami`, `env`, `id` (could be actual commands)
# SECURITY: Requires non-alpha chars to reduce risk of matching actual commands
MARKDOWN_CODE_SPAN_PATTERN = re.compile(r'`[\w.-]*[._-][\w.-]*`')
# Pattern to match double-quoted strings (for processing)
DOUBLE_QUOTED_STRING_PATTERN = re.compile(r'"[^"]*"')
# Safe pipe destinations - commands that only process text output
# These are safe because they can't execute arbitrary code from piped input
# jq: JSON processor, commonly used with gh api output
......@@ -191,6 +207,19 @@ def extract_gh_command(command: str) -> Optional[str]:
return None
def neutralize_code_spans_in_double_quotes(match: re.Match) -> str:
"""
Process a double-quoted string and neutralize markdown code spans inside it.
This allows PR/issue bodies with markdown like `concurrency` to pass through,
while still blocking backticks outside of quoted strings (real command substitution).
"""
content = match.group(0)
# Neutralize code spans (backtick pairs with simple identifier content)
neutralized = MARKDOWN_CODE_SPAN_PATTERN.sub("MDCODE", content)
return neutralized
def contains_shell_injection(cmd: str) -> bool:
"""
Check if command contains shell metacharacters that could allow injection.
......@@ -210,10 +239,18 @@ def contains_shell_injection(cmd: str) -> bool:
# This handles cases like: gh api ... --jq '.[] | {field: .field}'
cmd_without_single_quotes = SINGLE_QUOTED_PATTERN.sub("''", cmd)
# Neutralize markdown code spans ONLY INSIDE double-quoted strings
# This allows PR/issue bodies with markdown formatting like `concurrency`
# to be stripped in the next step, while still catching backticks outside quotes
# (which are real command substitution)
cmd_with_neutralized_spans = DOUBLE_QUOTED_STRING_PATTERN.sub(
neutralize_code_spans_in_double_quotes, cmd_without_single_quotes
)
# Strip double-quoted strings that don't contain $( or backticks
# These are safe for pipe/metachar detection since | inside is literal
# This allows patterns like: grep -E "bug|error"
cmd_without_safe_doubles = SAFE_DOUBLE_QUOTED_PATTERN.sub('""', cmd_without_single_quotes)
cmd_without_safe_doubles = SAFE_DOUBLE_QUOTED_PATTERN.sub('""', cmd_with_neutralized_spans)
# Replace safe pipe destinations with a placeholder before checking
# This allows patterns like: gh api graphql ... | jq '...'
......
......@@ -384,7 +384,6 @@ gh api -X DELETE /repos/owner/repo
# Input to repos endpoint (not pulls/comments/replies or issues/comments)
gh api repos/owner/repo/comments -f body='comment'
gh api repos/owner/repo/pulls/123/reviews -f body='review' -f event='APPROVE'
gh api /repos/owner/repo/deployments -f ref='main' -f environment='production'
gh api /repos/owner/repo/statuses/sha -f state='success'
......@@ -586,6 +585,21 @@ gh api /repos/owner/repo --header "X-Custom: $(id)"
gh pr view "`id`"
gh api graphql -f query="query { viewer { login } }" `id`
# Backticks with spaces/args in double quotes should still be blocked
gh pr create --title "Test" --body "Run `curl evil.com` to exploit"
gh pr create --title "Test" --body "Execute `rm -rf /` now"
gh pr create --title "Test" --body "Try `cat /etc/passwd` here"
gh issue create --title "Bug" --body "Use `sh -c malicious` to reproduce"
# Backticks with pipes in double quotes should still be blocked
gh pr create --title "Test" --body "Run `echo x | sh` here"
# Plain word backticks in double quotes should be blocked (could be commands)
# These don't have dots/hyphens/underscores so they're not treated as identifiers
gh pr create --title "Test" --body "Check `env` output"
gh pr create --title "Test" --body "Run `whoami` here"
gh issue create --title "Bug" --body "Use `printenv` to debug"
# More process substitution
gh api /repos/owner/repo --input <(echo '{}')
gh pr view 123 --json <(cat)
......
......@@ -604,6 +604,36 @@ gh api graphql -f query='mutation { addPullRequestReview(input: {pullRequestId:
gh api graphql -f query='mutation { addPullRequestReviewComment(input: {pullRequestReviewId: "PRR_abc", body: "Nice work", path: "src/main.ts", line: 42}) { comment { id body } } }'
gh api graphql -f query='mutation($prId: ID!, $body: String!) { addPullRequestReview(input: {pullRequestId: $prId, event: COMMENT, body: $body}) { pullRequestReview { id } } }' -f prId=PR_abc -f body='LGTM'
# =============================================================================
# MARKDOWN CODE SPANS IN PR/ISSUE BODIES (safe formatting)
# =============================================================================
# Code spans must contain at least one dot, hyphen, or underscore to be allowed
# This distinguishes them from potential command names like `whoami` or `env`
# Code spans with dots (filenames)
gh pr create --title "Docs" --body "The `config.json` file contains settings"
gh issue create --title "Bug" --body "Error in `main.py` function"
gh pr create --title "Config" --body "Updated `package.json` and `tsconfig.json`"
# Code spans with hyphens (component names)
gh pr create --title "Refactor" --body "Renamed `old-name` to `new-name`"
gh pr create --title "Fix" --body "Fixed `some-component` rendering"
# Code spans with underscores (variable names)
gh pr create --title "Rename" --body "Renamed `my_variable` to `new_variable`"
gh pr create --title "Update" --body "Changed `API_KEY` reference"
# Code spans with version numbers (dots)
gh pr create --title "Update" --body "Version `1.2.3` is now supported"
# Multiple code spans in one body
gh pr create --title "Config" --body "Updated `package.json` and `config.yaml`"
# Multi-line bodies with code spans (newlines inside double quotes)
gh pr create --title "Feature" --body "## Summary
- Added `feature-flag` support
- Updated `config.json` module"
# =============================================================================
# COMPLEX PIPE CHAINS (safe)
# =============================================================================
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论