fix(ci): dicht ongeauthenticeerde @claude-trigger (RCE op publieke repo)#25
Merged
Merged
Conversation
claude.yml draaide een agent met Bash + een schrijfrechten-token zodra een issue/comment de tekst "@claude" bevatte, zonder controle op wie de auteur is. Op deze publieke repo kon daardoor elke GitHub-gebruiker via een enkele comment code laten uitvoeren in een runner met het GITHUB_TOKEN en het CLAUDE_CODE_OAUTH_TOKEN. De job draait nu alleen wanneer de auteur OWNER, MEMBER of COLLABORATOR is, voor alle vier de triggers (issue_comment, pull_request_review_comment, pull_request_review, issues). claude-code-review.yml is defensief gehard: pull_request-velden lopen nu via env-variabelen in plaats van directe ${{ }}-interpolatie in het Bash-blok, zodat script-injectie via PR-metadata wordt voorkomen.
@v1 is een mutable tag: GitHub resolvet die bij elke run naar waar v1 op dat moment naar wijst. Een gecompromitteerde upstream-tag zou daarmee direct in de drie workflows landen die de agent met een write-scoped token draaien (claude, claude-code-review, api-sync). Alle drie nu gepind op het commit-SHA waar v1 nu naar wijst (51ea8ea), met '# v1' als leesbare annotatie. Conform de hardening- richtlijn van anthropics/claude-code-action zelf.
Twee aanvullende hardeningen bovenop de @claude-auth-gate:
1. id-token: write verwijderd uit claude, claude-code-review en
api-sync. Geen enkele step in deze workflows consumeert een
OIDC-token (geen configure-aws-credentials o.i.d.), dus de
permissie was dood gewicht. Met id-token: write kon een job
een OIDC-token munten met de identiteit van deze repo; relevant
voor claude-code-review omdat die op elke fork-PR draait.
2. claude-code-review draait nu alleen op same-repo PRs
(head.repo.fork == false). Die workflow checkt de PR-head uit
en de review-prompt leest bestanden uit die tree (CLAUDE.md
etc). Op een fork-PR is dat door een aanvaller bestuurde code,
met CLAUDE_CODE_OAUTH_TOKEN in de omgeving en Bash aan: een
klassieke prompt-injection-route. De env-var-hardening dekte
alleen ${{ }}-injectie, niet content-injectie uit de checkout.
api-sync zelf blijft ongewijzigd qua logica: die heeft al een
sanitize-step, gepinde oasdiff en draait niet op untrusted triggers.
Vorige commit verwijderde id-token: write in de aanname dat geen enkele step het OIDC-token consumeert. Dat was fout: claude-code-action gebruikt het token intern om te authenticeren tegen de Anthropic GitHub App. Zonder de permissie faalt elke run met: Failed to get OIDC token: Unable to get ACTIONS_ID_TOKEN_REQUEST_URL env variable id-token: write is hersteld op de drie jobs die de action draaien (claude, claude-review, api-sync/implement). De daadwerkelijke hardening tegen ongeauthenticeerd misbruik blijft de auth-gate (claude.yml) en de fork-gate (claude-code-review.yml): die zorgen dat het token niet vanuit een untrusted trigger bereikbaar is. De permissie zelf weghalen was geen mitigatie maar een storing.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Kwetsbaarheid
.github/workflows/claude.ymlstartte de Claude-agent zodra een issue, issue-comment, PR-review of PR-review-comment de tekst@claudebevatte. Deif:-conditie controleerde alleen of die string aanwezig was, niet wie de auteur is.Deze repo is publiek. Gevolg: elke GitHub-gebruiker kon door één comment te plaatsen een agent starten met:
--allowedTools Bash,Read,Glob,Grep,Edit,Write(shell + schrijftoegang)contents: write,pull-requests: write,issues: write,id-token: writesecrets.CLAUDE_CODE_OAUTH_TOKENEen aanvaller kon daarmee code uitvoeren in de runner, het
GITHUB_TOKENen het Claude-OAuth-token exfiltreren, naar de repo pushen, en viaid-tokenOIDC pivoten naar cloud-trust die deze repo-identiteit accepteert. Aanvalsoppervlak: het hele internet, één comment, geen voorafgaande toegang.Fix
claude.ymldraait de job nu alleen als de auteurOWNER,MEMBERofCOLLABORATORis. De gate staat op alle vier de triggers (issue_comment,pull_request_review_comment,pull_request_review,issues), telkens naast de bestaande@claude-check.claude-code-review.ymlis defensief meegehard (geen aparte kwetsbaarheid: die workflow draait oppull_requestmetcontents: readen zonderWrite-tool, dus een fork-PR krijgt een read-only token). PR-metadata loopt nu viaenv:-variabelen in plaats van directe${{ }}-interpolatie in het Bash-blok, zodat script-injectie via PR-titel/-velden structureel niet meer kan.Vervolgactie buiten deze PR
CLAUDE_CODE_OAUTH_TOKENmoet als mogelijk gecompromitteerd worden behandeld en geroteerd worden (gebeurt out-of-band, niet in deze PR). De fix sluit het gat, maar niet eventuele reeds gelekte token-waarde.Test
@claudeals niet-collaborator → job draait niet.@claudeals collaborator/member → job draait zoals voorheen.