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 |
|
@sin325 opened #27940 to satisfy status/need-issue and linked it here. I kept the exploit detail out of the public issue, but I'm happy to walk you or the team through the full thing privately if that's preferable. The change itself is just the workflow_run origin check described above — whatever's easiest to unblock the merge works for me. |
|
Hi there! Thank you for your interest in contributing to Gemini CLI. To ensure we maintain high code quality and focus on our prioritized roadmap, we only guarantee review and consideration of pull requests for issues that are explicitly labeled as 'help wanted'. This PR will be closed in 7 days if it remains without that designation. We encourage you to find and contribute to existing 'help wanted' issues in our backlog! Thank you for your understanding. |
|
This one isn't a roadmap/feature contribution — it's a security fix the team has already triaged and labeled Given that, could it be exempted from the auto-close and routed to the security/CI maintainer for review instead of the |
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.Resolves #27940