Turning Github Actions into an oracle
Ethan Heilman<br>Main || Writing
Turning Github Actions into an oracle<br>08-02-2025 7:23PM (ET) 09-08-2025 11:31PM (ET) (edited)
tl;dr - Instead of a complex Trusted Execution Environments like Intel SGX or AWS Nitro Enclave just use Github Actions.
One day while browsing the web you see an article on nasa.gov that says “scientists discover dragons are real.” You want to tell your friends that NASA is saying dragons are real, but then NASA deletes the article. You need a way to cryptographically prove nasa.gov had that article even after it is removed. To do this you need an oracle, more specifically need a TLS notary.
GitHub Actions (GHA)1 is far more powerful than it appears at first.<br>In this post I will look at an off-label use of GitHub Actions which allows it to be used as an oracle that can sign and notarize web content, including a TLS notary.<br>This allows a party to prove what content was on a website long into the future without requiring that anyone trust that party.<br>All anyone needs to trust is trust Github; not a github repo or a specific Github Action, but Github.<br>At the end we show how remove Github as a trusted party2.
The incredible James Carnegie (kipz) has written a working implementation of the ideas in this blog post:
URL Oracle - A Github Action that implements a TLS notary for any URL" github.com/kipz/url-oracle
BBC Technology News Oracle - An example use of URL Oracle that creates and verifies attestations for the BBC Technology RSS feed content to ensures the integrity and authenticity of BBC Technology news content through cryptographic attestations. github.com/kipz/bbc-tech-news-oracle
Disclaimer: While the features of GitHub Actions and GitLab-CI enable this functionality, this is an off-label use.<br>This is preliminary research, do not use this without first consulting with your personal cryptographer.<br>If you notice an increased appetite for trusted third parties, discontinue use immediately.
What our GitHub Action’s oracle does
While TLS notary is our main use case the functionality provided by this design goes well beyond a notary and provides an oracle for general purpose attestation of computation, i.e. Trusted Computing!<br>Such oracles are a useful and highly sought after security primitive for everything from software supply chain security, to blockchains and to cryptography.<br>We discuss these applications at the end of the post including how to use this oracle in OpenPubkey.
The oracle we create from GitHub Actions should have the following properties:
General Purpose: It will execute any program you give it.
Attestation: It will attest to the program it executed and the output of that program by signing the hash of the program and the hash of the output of the program.
Publicly Verifiable: This signature can be verified using GitHub’s public key.
Only Trust GitHub: The person who manages, configures and triggers the GitHub Action can not make the oracle lie or attest to the wrong program or output.
GitHub Actions (Program P): → GitHub’s Signature on: (SHA-1(P), SHA-1(Output of P))
Is SHA-1 safe? No, but the SHA-1 hash function used by GitHub and git is not actually SHA-1, but SHA1-DC, a variant of SHA-1 that has been hardened against collision attacks.
Background on GitHub Actions
GitHub Actions works by running a program in a github repo based on a workflow configuration file in that repo. Github spins up a container, downloads the repo into that container and then runs commands specified in the workflow config file. For instance for our oracle we tell it to checkout the repo, setup go, and run the main.go file.
steps:<br>- name: Checkout code<br>uses: actions/checkout@v4
- name: Set up Go<br>uses: actions/setup-go@v4<br>with:<br>go-version: 1.20.8
- name: Run Oracle<br>run: go run main.go
GitHub provides the ability for a program running in a GitHub Action to request an OpenID Connect ID Token from GitHub.<br>Requesting this ID Token is simple: core.getIDToken(audience), where audience can be any arbitrary string chosen by the program.<br>GitHub Actions will then return an ID Token signed by GitHub3.<br>GitHub ID Token’s look like:
"aud": nce string specified by program>,<br>"sha": -1 of the repo><br>"repository": "octo-org/octo-repo",<br>"workflow": "example-workflow",<br>"job_workflow_sha": -1 workflow commit>,<br>"iss": "https://token.actions.GitHubusercontent.com",<br>"exp": 1632493867,<br>"iat": 1632493567<br>… // Truncated
How to turn GitHub Actions into an oracle
An oracle needs to sign two things:
The hash of the program it ran
The hash of output it got from the program when it ran the program.
The ID Token already contains the hash of the program.<br>The only thing missing is the hash program output.<br>Remember when requesting an ID Token from GitHub the program specifies a string of its choice and GitHub sets that string as the audience in the ID Token.<br>Thus, to turn GitHub into an oracle, the program requests an ID Token with an audience set to the hash of...