-
-
We attacked our own system eight ways in one push — wrong account, repo, branch, workflow, event, environment, audience, and a forbiden trgt
-
A human retires the key, and Google's own ledger says why: USER_INITIATED. Every user-managed key on this account is now disabled.
-
Gemini interprets. Deterministic code proves. Humans authorize. One bounded transaction from stored key to keyless deploy.
-
The trust swap: one file, 202 lines, written by a human. The red line is the stored key leaving. The green lines are Workload Identity
-
The live evidence console on Cloud Run — public, read-only, and every gate links to a real run or a real Google audit entry.
Why we built this
29 million secrets leaked into public code last year. 64% of keys found valid four years ago are still live today. The US Treasury was breached using one API key belonging to a support vendor, and 57 million Uber records were stolen because credentials were committed to GitHub. In all these cases, the one vulnerability that made the attack possible was simple: the key existed.
Well, there's a known fix, called Workload Identity Federation. But without a safe path from legacy keys to that solution, there's no safe middle state. The middle steps that need to be traversed are these: correlate the GitHub secret to the exact Google key behind it, make the trust swap without causing breakage to the existing deployment, prove that the wrong identities indeed fail, and then retire the key, with proof that it was indeed done. This middle has been very hard to cross, and that middle is what Keyless Cutover closes.
What it does
Keyless Cutover crosses that middle as one bounded transaction that needs to run once, end to end, to retire the one offending key whose existence constitutes the vulnerability.
For each transaction, it proves possession of the key as follows: it creates a one-use, five-minute challenge in Firestore, signs it in memory using the key, and submits the signature to be verified. The signature comes out; the key never does. The challenge is consumed exactly once, and replays are explicitly rejected.
The surrounding evidence is then interpreted using Gemini 3.5 Flash on Vertex AI, in two tool-free stages, connected through the Google ADK. The output schema is fixed: one classification, ten IDs identifying evidence pieces, a capped explanation, and nothing else. No field in it can carry a workflow.
Separately, a deterministic compiler owns the migration itself. A human wrote the 202-line replacement workflow. The compiler recomputes the plan and refuses to proceed if the bytes differ. It is not possible for the model to write this file, by construction.
Once we've reached this point, Keyless Cutover proceeds to attack its own replacement work. It presents eight hostile identities, each targeting a single property that might be wrong in the replacement trust: the wrong account, the wrong repository, the wrong branch, the wrong workflow, the wrong triggering event, the wrong environment, the wrong federation audience, and a valid identity reaching for a forbidden service. All eight were denied, and denied again in a second independent transaction.
Sources for the numbers above: GitGuardian, State of Secrets Sprawl 2026 (29M new secrets on public GitHub in 2025, +34% year over year, the largest jump recorded; 64% of valid secrets from 2022 still not revoked in 2026) · U.S. DOJ, conviction of Uber's former CSO (57 million records, federal jury conviction) · The Hacker News on the Treasury/BeyondTrust breach (one compromised API key, December 2024)
Then the key is retired. A human disables it, and Google's own ledger records
DISABLE_REASON: USER_INITIATED. A fresh attempt to authenticate with the
dead key is refused by Google. Seven minutes later, the next deployment
succeeds keyless.
Lastly, for transparency, Keyless Cutover provides a public evidence console on Cloud Run, showing each gate and linking to the real GitHub run or the real Google Cloud audit entry behind it.
The boundary we cheerfully won't cross
Gemini interprets; deterministic code proves; humans authorize. Missing evidence stops the workflow; ambiguity yields HOLD, never an invented migration. The model has no IAM, no deploy authority, no merge authority, no key, and no shell authority.
We also integrated a second Google model, Gemma 4, as a baseline on the same sealed evaluation.
The part most teams would cut
Our verifier refused certification. It demanded exactly two post-disable
audit entries, and Google wrote three. So we recorded 81 real audit entries,
including the actual STS exchanges, and discovered our own verifier was
pinned to documentation, not real behavior. Real STS exchanges carry exactly
five request fields; federated tokens carry principalEmail; GitHub OIDC
subjects arrive ID decorated. We re-pinned all our checks to recorded
reality. Ten real exchanges verify; every forgery is rejected. Certification
now needs only one more transaction on the corrected checks using a fresh
key, because the disabled key is never re-enabled. And that refusal sits on
the public console, not in a private postmortem. Hiding failed verifications
is the very problem we started with.
What we learned
In the end, fail-closed is not a feature; it is a discipline. The hardest bug took days to find: our very own verifier trusting documentation over recorded bytes. We found it because the system refused to certify. Keeping the model out of the transaction path from start to end was exactly what the design wanted to achieve , it's not a limitation; it's the winning condition. And the evidence console changed our working style: now every claim needs a link to a real run or a real audit entry.
Built With
- cloud-audit-logs
- cloud-kms
- cloud-run
- firestore
- gemini
- github-actions
- google-adk
- google-cloud
- iam
- javascript
- node.js
- oidc
- sts
- vertex-ai
- workload-identity-federation
Log in or sign up for Devpost to join the conversation.