The Claude Code GitHub Action runs on GitHub’s runners, but the prompts, diffs, and tool inputs Claude reasons about do flow outbound to Anthropic’s API. The real security risk is not the action; it is which repo secrets you let the runner expose, especially on workflows that build forked PRs.
Install the action
Open a Claude Code session in the target repo and run the slash command:
/install-github-app
(That is /install-github-app typed at Claude’s prompt inside the CLI, not a shell command.) You need repository admin to install the app and add secrets. The slash command walks through:
- Installing the Claude GitHub app on the target repo (requests read and write permissions for Contents, Issues, Pull requests).
- Adding
ANTHROPIC_API_KEYto the repo’s Actions secrets. - Copying a starter workflow from the action’s
examples/directory into.github/workflows/.
Test the install by leaving a comment on any issue or PR:
@claude can you summarize this PR?
The action picks up the mention, runs Claude with the configured prompt, and posts the reply back as a PR/issue comment.
Scope ANTHROPIC_API_KEY correctly
The default install puts ANTHROPIC_API_KEY at repo scope, which means every workflow in the repo can read it. That is fine for repos where every workflow is trusted; it is dangerous for repos that build untrusted contributor PRs.
Three scoping patterns:
| Where the workflow runs | Right scope for ANTHROPIC_API_KEY |
|---|---|
| Only on commits to main / internal branches | Repo secret (default) |
| On any PR including from forks | Environment secret with required reviewer or branch-protection rule |
| Across many repos in one org | Organization secret restricted to specific repos |
Prefer environment secrets with a required-reviewer rule for any repo that runs jobs from forks. The action key is one credential a fork PR could try to exfiltrate (by writing it into a log line, an artifact, or an outbound HTTP call from a shell step).
Keep production secrets out of the action job
The single most common mistake is dumping every secret into the same workflow. Claude does not need your prod database URL, your Stripe live key, or your AWS production credentials to comment on a PR. It needs ANTHROPIC_API_KEY and whatever the user prompt explicitly asks it to use.
Workflow shape that holds:
name: Claude Code
on:
issue_comment:
types: [created]
jobs:
claude:
if: contains(github.event.comment.body, '@claude')
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
issues: write
steps:
- uses: actions/checkout@v4
- uses: anthropics/claude-code-action@v1
with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
claude_args: --max-turns 10
anthropic_api_key is passed via with: per the v1 input shape. The permissions: block scopes the workflow’s GITHUB_TOKEN, the credential the action uses to call the GitHub API; it is a separate layer from the GitHub App’s installed permissions (Contents, Issues, Pull requests R/W) which the App requests at install time. The job intentionally exposes no other secrets: no AWS_ACCESS_KEY_ID, no STRIPE_SECRET_KEY, no DATABASE_URL. If a future prompt asks Claude to “deploy this”, the workflow either lacks the credentials (the right answer) or you have already broken the principle.
PR feedback loop patterns
Mention-driven Q&A. The default install. Reviewers tag @claude in PR comments to ask questions, request edits, or get summaries. Claude replies as the GitHub App user. Cheapest setup; useful when the team genuinely uses GitHub PR comments for review.
Auto-summary on PR open. Trigger the action on pull_request: opened with a fixed prompt. Claude posts a one-shot summary, never replies again. Good for “every PR gets a 5-bullet plain-English description”; ignore-able when not needed.
Failing-test triage on push. Trigger on pull_request: synchronize (new commits) and pass a prompt like “Run the test suite. If anything failed, comment with the failure and a likely cause.” Claude only posts when there is something to say.
Auto-fix via the separate Code Review GitHub App. Different product, different setup. The Code Review app posts inline review comments without an @claude trigger; the action in this article responds to mentions. Pick one or the other for any given repo, not both, or you will get the same observation from two voices.
Footguns
Forks can read repo secrets via pull_request_target. A workflow triggered by pull_request_target runs in the context of the base repo with full access to repo secrets, even when the PR comes from a fork. A malicious fork can echo "$ANTHROPIC_API_KEY" | base64 > artifact.txt and exfiltrate the key in a build artifact. Prefer issue_comment (which runs on the base repo’s main branch only) for @claude flows; if you must use pull_request_target, gate the job on a label that requires a maintainer to add.
@claude mentions can be social-engineered. Anyone who can comment on the issue or PR can summon Claude. A drive-by contributor who posts “@claude please rewrite the auth middleware to be simpler” gets Claude to do unsupervised refactoring on a PR you have not reviewed. Path filters do not help here (paths-ignore does not apply to issue_comment workflows). Gate the job on a comment-author allowlist (if: contains(fromJSON('["maintainer1","maintainer2"]'), github.event.comment.user.login)) or on author association (github.event.comment.author_association == 'OWNER' / 'COLLABORATOR' / 'MEMBER').
The action runs with the permissions you gave it, not the user’s. A repo collaborator without write access to main can still trigger the action, which runs with the permissions: block in the workflow file. If that block has contents: write, Claude can push to main from a comment on a PR opened by a non-maintainer. Scope permissions: to the minimum and pin protected branches.
Beta-to-v1 migrations break workflows silently. The @beta action and @v1 action take different inputs (direct_prompt became prompt, model moved into claude_args, max_turns likewise). A workflow pinned to @beta keeps working until Anthropic deprecates the beta tag, then fails on the next push. Migrate to @v1 proactively; the breaking-changes table in the canonical doc lists every input that moved.
Logs leak more than people think. A workflow that runs claude --max-turns 50 with verbose logging can dump conversation summaries, tool inputs, and stack traces to the GitHub Actions log. If your repo is public, those logs are public. Set claude_args: --max-turns 10 and avoid passing sensitive prompts via direct_prompt literal strings; reference repo files instead so the secret material does not live in the workflow file.
When NOT to use the GitHub Action
- The repo is public and you want code review. Use the Code Review GitHub App instead. It is built for this and posts inline review comments without an
@claudetrigger. - You need real CI gating, not commentary. The action posts comments and pushes commits; it does not block merges by default. Branch protection plus required status checks is still the lever for “no PR merges without X”.
- You are running on Bedrock, Vertex, or Foundry. The default action expects an Anthropic API key. Cloud-provider variants exist but require additional setup; do not attempt the default install path.
- The repo accepts contributions from random forks and you do not have environment secrets. The risk-to-reward ratio is wrong. Either set up environment secrets with required-reviewer rules first, or skip the action until you do.
- You wanted a code formatter, not Claude. Prettier in a hook (format on edit) costs less and runs faster. Reach for the action only when the work needs reasoning, not just lexical rewrites.