From eaf2096104ef644615688810fd89f57259372efe Mon Sep 17 00:00:00 2001 From: Matt McKay Date: Sun, 26 Jul 2026 19:42:26 +1000 Subject: [PATCH] security: gate the \translate-resync trigger on commenter trust (all 3 languages) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The issue_comment clause checked only that the comment body contained the magic string. issue_comment workflows run in default-branch context with full access to secrets, so on a public repo any GitHub account could comment \translate-resync on a merged PR and spend Anthropic credits and runner minutes, repeatedly. The clause now also requires the comment to be on a pull request (plain issues raise the same event) and its author to be an OWNER, MEMBER or COLLABORATOR. Adds permissions: contents: read — the action authenticates with QUANTECON_SERVICES_PAT, so the ambient GITHUB_TOKEN never needs write. Applied identically to the zh-cn, fa and fr sync workflows. Ports the shape from QuantEcon/action-translation#192. Triggers, paths filters, inputs and the @v0 pin are unchanged. Co-Authored-By: Claude Opus 5 (1M context) --- .github/workflows/sync-translations-fa.yml | 13 ++++++++++++- .github/workflows/sync-translations-fr.yml | 13 ++++++++++++- .github/workflows/sync-translations-zh-cn.yml | 13 ++++++++++++- 3 files changed, 36 insertions(+), 3 deletions(-) diff --git a/.github/workflows/sync-translations-fa.yml b/.github/workflows/sync-translations-fa.yml index ef0c958b..b5629555 100644 --- a/.github/workflows/sync-translations-fa.yml +++ b/.github/workflows/sync-translations-fa.yml @@ -14,11 +14,22 @@ on: jobs: sync: + # The issue_comment path requires all three: a comment on a PR (not a bare + # issue), the command, and a trusted author — otherwise any account could + # fire a secrets-bearing run (Anthropic spend plus the PAT) from any comment. if: > (github.event_name == 'pull_request' && github.event.pull_request.merged == true) || - (github.event_name == 'issue_comment' && contains(github.event.comment.body, '\translate-resync')) + (github.event_name == 'issue_comment' && + github.event.issue.pull_request && + contains(github.event.comment.body, '\translate-resync') && + contains(fromJSON('["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.comment.author_association)) runs-on: ubuntu-latest + # The action authenticates with QUANTECON_SERVICES_PAT; the ambient + # GITHUB_TOKEN is unused beyond checkout, so keep it read-only. + permissions: + contents: read + steps: - uses: actions/checkout@v7 with: diff --git a/.github/workflows/sync-translations-fr.yml b/.github/workflows/sync-translations-fr.yml index 11b20591..e8fc8bdd 100644 --- a/.github/workflows/sync-translations-fr.yml +++ b/.github/workflows/sync-translations-fr.yml @@ -14,11 +14,22 @@ on: jobs: sync: + # The issue_comment path requires all three: a comment on a PR (not a bare + # issue), the command, and a trusted author — otherwise any account could + # fire a secrets-bearing run (Anthropic spend plus the PAT) from any comment. if: > (github.event_name == 'pull_request' && github.event.pull_request.merged == true) || - (github.event_name == 'issue_comment' && contains(github.event.comment.body, '\translate-resync')) + (github.event_name == 'issue_comment' && + github.event.issue.pull_request && + contains(github.event.comment.body, '\translate-resync') && + contains(fromJSON('["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.comment.author_association)) runs-on: ubuntu-latest + # The action authenticates with QUANTECON_SERVICES_PAT; the ambient + # GITHUB_TOKEN is unused beyond checkout, so keep it read-only. + permissions: + contents: read + steps: - uses: actions/checkout@v7 with: diff --git a/.github/workflows/sync-translations-zh-cn.yml b/.github/workflows/sync-translations-zh-cn.yml index a92810cc..9296d879 100644 --- a/.github/workflows/sync-translations-zh-cn.yml +++ b/.github/workflows/sync-translations-zh-cn.yml @@ -14,11 +14,22 @@ on: jobs: sync: + # The issue_comment path requires all three: a comment on a PR (not a bare + # issue), the command, and a trusted author — otherwise any account could + # fire a secrets-bearing run (Anthropic spend plus the PAT) from any comment. if: > (github.event_name == 'pull_request' && github.event.pull_request.merged == true) || - (github.event_name == 'issue_comment' && contains(github.event.comment.body, '\translate-resync')) + (github.event_name == 'issue_comment' && + github.event.issue.pull_request && + contains(github.event.comment.body, '\translate-resync') && + contains(fromJSON('["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.comment.author_association)) runs-on: ubuntu-latest + # The action authenticates with QUANTECON_SERVICES_PAT; the ambient + # GITHUB_TOKEN is unused beyond checkout, so keep it read-only. + permissions: + contents: read + steps: - uses: actions/checkout@v7 with: