From add93e12dfaf791b56c6156dd083184a871c585b Mon Sep 17 00:00:00 2001 From: Benjamin Outland Date: Tue, 21 Apr 2026 10:08:14 -0500 Subject: [PATCH] fix: harden Claude Code Actions against prompt injection (Comment and Control CVE) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Addresses the "Comment and Control" vulnerability class disclosed 2026-04-21 affecting anthropics/claude-code-action@v1. PR titles, issue bodies, and comments can be weaponized to hijack the AI agent and exfiltrate secrets (CLAUDE_CODE_OAUTH_TOKEN, GITHUB_TOKEN) via CI/CD environments. Hardening applied to both workflows: 1. Actor gating — only trusted users trigger the action - claude-code-review.yml: gate by PR author login + OWNER/MEMBER association - claude.yml: gate by github.actor and sender.login 2. Tool restriction — prevent dangerous actions even if injection fires - Added: claude_args: --disallowed-tools Bash,Write,WebFetch,Edit,NotebookEdit - Review and analysis still function; write/exec blocked 3. Least privilege — removed unnecessary id-token:write permission - OIDC token no longer exposed to action context Ref: https://x.com/the_cyber_news/status/2046510893752807689 --- .github/workflows/claude-code-review.yml | 24 +++++++------------ .github/workflows/claude.yml | 30 +++++++++++------------- 2 files changed, 23 insertions(+), 31 deletions(-) diff --git a/.github/workflows/claude-code-review.yml b/.github/workflows/claude-code-review.yml index b5e8cfd4..0916fecb 100644 --- a/.github/workflows/claude-code-review.yml +++ b/.github/workflows/claude-code-review.yml @@ -3,27 +3,22 @@ name: Claude Code Review on: pull_request: types: [opened, synchronize, ready_for_review, reopened] - # Optional: Only run on specific file changes - # paths: - # - "src/**/*.ts" - # - "src/**/*.tsx" - # - "src/**/*.js" - # - "src/**/*.jsx" jobs: claude-review: - # Optional: Filter by PR author - # if: | - # github.event.pull_request.user.login == 'external-contributor' || - # github.event.pull_request.user.login == 'new-developer' || - # github.event.pull_request.author_association == 'FIRST_TIME_CONTRIBUTOR' + # HARDENED (Comment and Control vulnerability — 2026-04-21) + # Only run for trusted PR authors. Untrusted forks cannot trigger this. + if: | + github.event.pull_request.user.login == 'zerodarkthirtyhq' || + github.event.pull_request.author_association == 'OWNER' || + github.event.pull_request.author_association == 'MEMBER' runs-on: ubuntu-latest + # Least-privilege permissions — removed id-token:write (not needed) permissions: contents: read pull-requests: read issues: read - id-token: write steps: - name: Checkout repository @@ -39,6 +34,5 @@ jobs: plugin_marketplaces: 'https://github.com/anthropics/claude-code.git' plugins: 'code-review@claude-code-plugins' prompt: '/code-review:code-review ${{ github.repository }}/pull/${{ github.event.pull_request.number }}' - # See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md - # or https://code.claude.com/docs/en/cli-reference for available options - + # HARDENED: Restrict dangerous tools to prevent prompt injection exploitation + claude_args: '--disallowed-tools Bash,Write,WebFetch,Edit,NotebookEdit' diff --git a/.github/workflows/claude.yml b/.github/workflows/claude.yml index d300267f..41ac2dc2 100644 --- a/.github/workflows/claude.yml +++ b/.github/workflows/claude.yml @@ -12,17 +12,24 @@ on: jobs: claude: + # HARDENED (Comment and Control vulnerability — 2026-04-21) + # Require @claude mention AND trusted actor. Untrusted users cannot trigger. if: | - (github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) || - (github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) || - (github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) || - (github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude'))) + ( + (github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) || + (github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) || + (github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) || + (github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude'))) + ) && ( + github.actor == 'zerodarkthirtyhq' || + github.event.sender.login == 'zerodarkthirtyhq' + ) runs-on: ubuntu-latest + # Least-privilege — removed id-token:write (not needed) permissions: contents: read pull-requests: read issues: read - id-token: write actions: read # Required for Claude to read CI results on PRs steps: - name: Checkout repository @@ -35,16 +42,7 @@ jobs: uses: anthropics/claude-code-action@v1 with: claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} - - # This is an optional setting that allows Claude to read CI results on PRs additional_permissions: | actions: read - - # Optional: Give a custom prompt to Claude. If this is not specified, Claude will perform the instructions specified in the comment that tagged it. - # prompt: 'Update the pull request description to include a summary of changes.' - - # Optional: Add claude_args to customize behavior and configuration - # See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md - # or https://code.claude.com/docs/en/cli-reference for available options - # claude_args: '--allowed-tools Bash(gh pr:*)' - + # HARDENED: Restrict dangerous tools to prevent prompt injection exploitation + claude_args: '--disallowed-tools Bash,Write,WebFetch,Edit,NotebookEdit'