From 13dd81699009290e105b7d832d55c21fe214cf1b Mon Sep 17 00:00:00 2001 From: ci Date: Thu, 27 Aug 2026 17:29:00 -0400 Subject: [PATCH 1/2] Gate the @claude mention workflow on the operator MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The repo went public today with this workflow ungated, so any passer-by could spend the operator's subscription by writing "@claude" in a comment. It now checks both actors, the rule every other job here follows — on a re-run github.actor stays whoever started the original run, and the person who pressed re-run appears only in github.triggering_actor. Bots stay refused deliberately: the action rejects bot actors unless listed in allowed_bots, and no bot edge is opened here. Cross-vendor review belongs in a workflow that fires on every PR, not in a mention edge where one bot can spend the operator's quota by talking to another. Co-Authored-By: Claude Fable 5 --- .github/workflows/claude.yml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/.github/workflows/claude.yml b/.github/workflows/claude.yml index 1a072c9..18bdb25 100644 --- a/.github/workflows/claude.yml +++ b/.github/workflows/claude.yml @@ -1,5 +1,20 @@ name: Claude Code +# Answers @claude mentions on issues and PRs. +# +# ACTOR GATE — this repo is public, so without it any passer-by could spend the +# operator's subscription by writing "@claude" in a comment. Both actors are +# checked, the same rule every job in this repo follows: on a re-run +# github.actor stays whoever started the original run, and the person who +# pressed re-run appears only in github.triggering_actor, so checking one alone +# lets a collaborator re-run someone else's job. +# +# Bots stay refused: the action rejects bot actors unless they are listed in +# allowed_bots, and no bot edge is opened here on purpose. A cross-vendor +# reviewer belongs in a review workflow that fires on every PR, not in a +# mention edge where one bot can spend the operator's quota by talking to +# another. + on: issue_comment: types: [created] @@ -13,10 +28,14 @@ on: jobs: claude: if: | + github.actor == 'yihanzhu' && + github.triggering_actor == 'yihanzhu' && + ( (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'))) + ) runs-on: ubuntu-latest permissions: contents: read From d4c8b72d28b65015207ebfaa6fc285b84a708d77 Mon Sep 17 00:00:00 2001 From: ci Date: Thu, 27 Aug 2026 17:33:03 -0400 Subject: [PATCH 2/2] Gate issue events on the issue's author, not just the actor MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Codex [Security]: the actor gate says who triggered the event, not who wrote the text the agent then reads. On `issues: assigned` the actor is the operator doing triage while the body belongs to whoever opened the issue — so a stranger could file an issue containing "@claude" and instructions, and it would run the moment it was assigned. Issue events now also require the issue author to be the operator. Comment events need no separate check: there the actor is the author. The general shape, worth carrying: gate on the provenance of the CONTENT an agent will act on, not only on who fired the event. Co-Authored-By: Claude Fable 5 --- .github/workflows/claude.yml | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/.github/workflows/claude.yml b/.github/workflows/claude.yml index 18bdb25..26c864d 100644 --- a/.github/workflows/claude.yml +++ b/.github/workflows/claude.yml @@ -9,6 +9,14 @@ name: Claude Code # pressed re-run appears only in github.triggering_actor, so checking one alone # lets a collaborator re-run someone else's job. # +# AUTHOR GATE — the actor gate alone is not enough. It says who triggered the +# event, not who wrote the text the agent will then read. On `issues: assigned` +# the actor is the operator doing triage while the issue body belongs to +# whoever opened it, so a stranger's issue containing "@claude" plus +# instructions would run the moment it is assigned. Issue events therefore also +# require the ISSUE AUTHOR to be the operator. (Comment events need no separate +# check: there the actor IS the author.) +# # Bots stay refused: the action rejects bot actors unless they are listed in # allowed_bots, and no bot edge is opened here on purpose. A cross-vendor # reviewer belongs in a review workflow that fires on every PR, not in a @@ -34,7 +42,9 @@ jobs: (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 == 'issues' && + github.event.issue.user.login == 'yihanzhu' && + (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude'))) ) runs-on: ubuntu-latest permissions: