Skip to content

fix(ci): support external contributors in Claude workflows - #316

Merged
thomhurst merged 1 commit into
mainfrom
fix/claude-external-users
Sep 4, 2026
Merged

fix(ci): support external contributors in Claude workflows#316
thomhurst merged 1 commit into
mainfrom
fix/claude-external-users

Conversation

@thomhurst

Copy link
Copy Markdown
Owner

Summary

  • allow Claude issue triage and pull request reviews for contributors without repository write access
  • pass the scoped GITHUB_TOKEN explicitly and opt in via allowed_non_write_users
  • isolate untrusted issue/PR content behind pinned-target helper scripts, minimal permissions, and narrow tool allowlists
  • port the fixes from TUnit #6720 and TUnit #6722

Validation

  • actionlint 1.7.12 (both workflows)
  • PyYAML parse (both workflows)
  • bash -n (both helper scripts)
  • helper behavior checks for pinned targets, valid forwarding, invalid-label rejection, and empty-comment rejection

Pass the scoped GITHUB_TOKEN explicitly because the Claude OIDC token exchange rejects users without write access.

Isolate untrusted issue and pull request input behind pinned write helpers before using pull_request_target.
@thomhurst
thomhurst deployed to Pull Requests September 4, 2026 16:59 — with GitHub Actions Active
@coderabbitai

coderabbitai Bot commented Sep 4, 2026

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Team

Run ID: f13e7785-23d2-4263-b2c6-fd2e6609f514


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 4, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-04T17:04:40.973334Z ed77eef PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ed77eefd62

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".


Use the code review skill to run this review: /code-review:code-review ${{ github.repository }}/pull/${{ github.event.pull_request.number || inputs.pr_number }}
claude_args: |
--add-dir pr-head --allowedTools "Read,Glob,Grep,Bash(.github/scripts/pr-review-comment.sh:*),Bash(gh pr view:*),Bash(gh pr diff:*),Bash(git diff:*),Bash(git log:*),Bash(git show:*)"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Remove write-capable Git commands from the allowlist

When untrusted PR content persuades Claude to invoke an approved Git command, git log --format=... --output=.github/scripts/pr-review-comment.sh can replace the helper with attacker-chosen shell code while preserving its executable mode; Git documents --output=<file> as “output to a specific file instead of stdout” in its diff options. Claude can then invoke the replaced helper under the separate allowlist entry and execute arbitrary commands with the write-capable token, completely bypassing the pinned-PR restriction. Expose Git through a wrapper that rejects output/config/execution options, or keep the privileged helper outside the model-writable workspace.

Useful? React with 👍 / 👎.

type: number

concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Use the pull request identity in the concurrency key

For external PRs, github.head_ref contains only the source branch name and does not include the fork owner or PR number. Two contributors commonly using a branch such as fix therefore share this concurrency group, so opening or synchronizing one PR cancels the other PR's in-progress review and leaves it without the promised comment. Key automatic runs by github.event.pull_request.number (and manual runs by inputs.pr_number) instead.

Useful? React with 👍 / 👎.

@greptile-apps

greptile-apps Bot commented Sep 4, 2026

Copy link
Copy Markdown

Greptile Summary

This PR enables Claude review and issue-triage workflows for external contributors by moving review execution to pull_request_target, explicitly supplying scoped workflow tokens, isolating the PR checkout, and routing writes through constrained helper scripts.

  • Adds pinned-target helpers for PR comments and issue labels/comments.
  • Adds external-contributor issue triage with minimal workflow permissions.
  • Isolates untrusted PR files and limits the model's available tools.
  • Leaves the review checkout credential model-readable and uses mutable references for privileged actions; both should be addressed before merging.

Confidence Score: 3/5

The PR is not yet safe to merge because untrusted PR content is processed while a write-scoped checkout credential remains readable by the model.

The constrained helpers and isolated PR checkout are sound, but the base checkout's persisted credential creates a concrete source-to-public-comment disclosure path; immutable action pinning is also needed to harden these privileged workflows.

Files Needing Attention: .github/workflows/claude-code-review.yml and .github/workflows/claude-issue-triage.yml

Security Review

Two security concerns were identified:

  • The trusted base checkout persists a pull-request-write token in model-readable Git credential configuration, creating a prompt-injection path to disclose it through the permitted comment helper.
  • Privileged actions receiving OAuth and write-scoped workflow credentials are referenced through mutable tags rather than immutable commit SHAs.

Important Files Changed

Filename Overview
.github/workflows/claude-code-review.yml Enables external PR review with an isolated head checkout and narrow tools, but leaves the write-scoped base-checkout credential accessible to the model.
.github/workflows/claude-issue-triage.yml Adds minimally scoped external issue triage, with the remaining concern that credential-bearing actions use mutable tags.
.github/scripts/pr-review-comment.sh Safely pins review comments to the workflow-selected repository and PR while rejecting empty bodies.
.github/scripts/triage-issue.sh Restricts issue writes to labels and comments on the workflow-selected issue, with quoted arguments and label validation.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    External[External contributor] --> Event[Issue or pull-request event]
    Event --> Workflow[Trusted base-repository workflow]
    Workflow --> Base[Trusted base checkout]
    Workflow --> Head[Untrusted PR head in pr-head/]
    Base --> Credential[Persisted Git credential]
    Head --> Claude[Claude action with restricted tools]
    Credential --> Claude
    Claude --> ReviewHelper[Pinned PR-comment helper]
    Claude --> TriageHelper[Pinned issue-triage helper]
    ReviewHelper --> PR[Triggering pull request]
    TriageHelper --> Issue[Triggering issue]
Loading

Reviews (1): Last reviewed commit: "fix(ci): support external contributors" | Re-trigger Greptile

Comment on lines +48 to +51
- name: Checkout base repository
uses: actions/checkout@v7.0.1
with:
fetch-depth: 1

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 security Readable Write Token

The trusted base checkout keeps persist-credentials enabled by default. As a result, its write-scoped GITHUB_TOKEN remains available through Git credential configuration while Claude has unrestricted Read access and processes attacker-controlled pull request content. A prompt-injected review could read the credential and pass it to the arbitrary-body comment helper, publicly disclosing a live token capable of modifying pull requests. Disable credential persistence on the base checkout and keep credentials outside model-readable paths.

How this was verified: The base checkout persists the write-scoped token, unrestricted Read reaches the checkout's Git configuration, and the permitted helper posts any nonempty supplied body to the attacker-visible pull request.

Suggested change
- name: Checkout base repository
uses: actions/checkout@v7.0.1
with:
fetch-depth: 1
- name: Checkout base repository
uses: actions/checkout@v7.0.1
with:
fetch-depth: 1
persist-credentials: false

with:
fetch-depth: 1

- uses: anthropics/claude-code-action@v1

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 security Mutable Privileged Actions

The new triage workflow runs anthropics/claude-code-action@v1 and actions/checkout@v7.0.1 through mutable tags while supplying an OAuth secret and an issues-write token. The review workflow also uses mutable references while handling external contributions. If an upstream tag is moved or compromised, replacement action code could access these credentials and make unauthorized issue or pull request changes. Pin these actions to full commit SHAs, as the repository's other production workflows do.

How this was verified: The mutable Claude action receives both explicitly supplied credentials, and the repository's other workflows pin the same checkout release to a full commit SHA.

@thomhurst
thomhurst merged commit 890bd71 into main Sep 4, 2026
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant