-10-
Grand Theft Actions: Abusing Self-Hosted GitHub Runners at Scale - Adnan Khan, John Stawinski
GitHub Actions is a CI/CD tool that lets you run code (workflows) in response to events. Being code and all—it needs something to run on.
The default option is GitHub runners - an ephemeral VM. Another option, more commonly used for large repos, is self-hosted runners— bringing your own machine to run workflows on.
Self-hosted runners are a security nightmare. Clearly shown throughout this talk, the main issue is that they’re persistent, so any vulnerability in self-hosted workflows is amplified.
Jumping ahead, the talk presents many attack techniques against self-hosted runners, nicely concluded by John in this diagram: https://github.com/jstawinski/Github-Actions-Attack-Diagram
The research found vulnerabilities in dozens of high profile orgs, but the talk itself focuses on PyTorch. So what’s the recipe for hacking into self-hosted runners?
First: become a contributor. The default config only blocks first-time contributors from running workflows, so after the first approved PR— it's a free game.
Find a simple grammar mistake and fix it in a quickly accepted PR, becoming a contributor in the process. From then on, you can run workflows on the self-hosted runner using PRs from your fork.
Then, gain persistence: since the machine might be protected, the researchers take a safe approach and deploy another self-hosted runner agent that connects to a private repo. Neat!
Next, steal GITHUB_TOKEN
— a secret allowing access to GitHub for the workflow. However, in fork PRs these have read only access. But, workflows share the self-hosted runner, so after gaining persistence access they simply stole a GITHUB_TOKEN
from another workflow from the base repo.
With such a token, there are many options for supply chain attack, like changing release assets!
But it wasn’t enough for Adnan and John— they wanted to steal real secrets from workflows. These would most likely escalate their privilege into the PyTorch organization.
It only takes compromising one workflow using these secrets. But, the already-compromised workflow did not use them, and the stronger GITHUB_TOKEN
cannot modify the workflows directory.
The solution is simple— they found a workflow depending on a Python code from outside the workflow directory. Now, all that's needed is use GITHUB_TOKEN
to create a branch, add a payload to the Python code that dumps the secrets to logs, trigger the workflow with the, and retrieve the secrets from the logs.
The stolen secrets contained a GitHub personal access token with wide access to PyTorch’s private repos, as well as an AWS access key with highly privileged access to PyTorch’s AWS account.
And, just like that, becoming a contributor with a simple PR led to full compromise of PyTorch’s GitHub and AWS, which could have led to catastrophic consequences had it not been for this research. Amazing work!
https://www.youtube.com/watch?v=5P7KatZBr_I