ci: validate workflow_run origin before consuming the E2E artifact (fixes fork artifact poisoning)#27753
Conversation
The chained E2E workflow runs on `workflow_run` in the base-repo context with GEMINI_API_KEY, GEMINI_CLI_ROBOT_GITHUB_PAT, and a write-all GITHUB_TOKEN in scope. `download_repo_name` downloads the repo_name/head_sha artifact produced by the `Trigger E2E` run (which runs on `pull_request`, including forks) and the downstream jobs check out and build that repository/sha. A fork PR can write its own repo and SHA into the artifact, causing the privileged workflow to execute attacker-controlled code (`npm ci`/`postinstall`, build, tests) with those secrets available. Gate artifact consumption on the triggering run's `head_repository` being this repository, so a fork-triggered run falls back to the base repo/sha and does not run fork code with secrets. The existing `github.repository` check is always true under `workflow_run` and does not validate the artifact's origin.
|
Note Gemini is unable to generate a summary for this pull request due to the file types involved not being currently supported. |
|
📊 PR Size: size/S
|
|
Thanks for taking a look @sin325. The A couple of ways to unblock, whichever your team prefers:
On the change itself: the diff gates |
Summary
The chained E2E pipeline is vulnerable to
workflow_runartifact poisoning, allowing a fork PR to run attacker-controlled code with repository secrets.trigger_e2e.ymlruns onpull_request(including forks) and writes the PR headrepo.full_nameandshainto therepo_nameartifact.chained_e2e.ymlruns onworkflow_run(base-repo context, full secret access).download_repo_namedownloads that artifact and the downstream jobs (e2e_linux,e2e_mac,e2e_windows,evals)actions/checkoutthe artifact'srepository/shaand runnpm ci(executingpostinstall),npm run build, and tests withGEMINI_API_KEY,GEMINI_CLI_ROBOT_GITHUB_PAT, andpermissions: write-allin scope.A fork can therefore put its own repo + SHA into the artifact and have the privileged workflow execute its code with those secrets. The existing
github.repository == 'google-gemini/gemini-cli'guard is always true underworkflow_run(it runs in the base context) and does not validate the artifact's origin.This is the
workflow_runartifact-poisoning pattern documented by GitHub Security Lab.Fix
Gate artifact consumption (
download_repo_name) on the triggering run'shead_repositorybeing this repository:For a fork-triggered run this skips the artifact download, so
parse_run_contextfalls back togithub.repository/baseshaand the E2E jobs no longer check out or execute fork code with secrets. Same-repo PRs andworkflow_dispatchare unaffected.Note on fork E2E
This change intentionally stops the secret-bearing E2E jobs from running fork code. If you want to keep E2E coverage for fork PRs, the safe pattern is to gate it behind a human-applied label (or a deployment environment with required reviewers) before checking out fork code with secrets — similar to how other Google repos (e.g.
protocolbuffers/protobuf) require a "safe for tests" label on fork PRs. Happy to follow up with that if preferred.