Github and github_token and github secrets

So GitHub is the thing now! Everyone is migrating to GitHub leaving their Azure DevOps or whatever they were using for the benefit of GitHub. And, I understand! GitHub is simple, and also is this new shiny thing (not as an open source git but as an enterprise DevOps platform). For example it is very easy to define secrets to use via action workflows. And even use ‘GitHub token’ to do things on behalf of you. Since Microsoft acquired GitHub, they are investing heavily on monetizing it (for organizations not open source). So, lots of good features are added literary everyday. But it seems GitHub is not there yet, there are really scary security flaws around for organizations.

GitHub secrets

GitHub secrets are encrypted strings you put in your GitHub repository or organization to pass it to your GitHub workflows actions when they are running. You create them from Settings > Secrets. So if you have for example a third party API that does something with your workflow, you need to put the API access information to secrets.

For example in case of SonarQube to scan your pull request you set the URL and Token as secrets. Then within your workflow, you access them like ${{ secrets.MySecret }}.

The good thing about it is that GitHub has a protection mechanism that if you log the GitHub secrets it is changed to *** , and GitHub UI doesn’t reveal them either . You can feel safe about it; seems no one can retrieve! It might mislead you so you feel safe to put sensitive information in GitHub secrets, but please don’t! I am going to tell you why in a second.

GitHub token

GitHub token is actually a short lived token generated by GitHub. It can do things on the repository without needing your username and password. For example, when we run checkout action (uses: actions/checkout@v2 to checkout our repo to the agent running the workflow), it is actually internally uses github_token. You can use this token in your workflow like ${{ secrets.GITHUB_TOKEN }} or if you are writing an action (like the checkout) you can use it like github.token instead of secrets.GITHUB_TOKEN. This is really powerful, and an unleashed powerful thing is a recipe for disaster! I am showing you why in a moment.

Security flaw of GitHub secrets

Ok let’s get to the part I tell you how things can go wrong. Just before you panic, we assumed that you have contributors in your repository that you don’t fully trust. They can contribute directly to your repository but you protect your main/master branch. This way, you make sure they don’t merge code they should not with your code base. You also have your secrets encrypted and safe on GitHub. So you really feel comfortable that your secrets are safe with GitHub and cannot be decrypted and retrieved. But you know that if you can pass the secret to your third party you can pass it to any third party! As a matter of fact, you don’t even need to do that! Just put a spaces between characters of your secret and GitHub reveals your secrets in the logs (please don’t do that!):

echo ${{ secrets.MySecret }} | sed -e 's/\(.\)/\1 /g' 

So a contributor with write access can make a new branch and make a new workflow on that branch (or even change an existing one) and retrieve the secrets using echo command and sed. Not much of a secret right?

name: Retrieve secrets 
on:
  push:
  workflow_dispatch:
jobs:
  log-secret:
    runs-on: ubuntu-latest
    steps:
      - name: Run a multi-line script
        run: |
          echo ${{ secrets.MySecret }} # prints ***
          echo ${{ secrets.MySecret }} | sed -e 's/\(.\)/\1 /g' # prints the secrets with spaces 

Don’t let github masking a log file gives you a false feeling of safety. As you see at the last line above a malicious contributor can retrieve your secrets easily.

The Solution for keeping GitHub Secret safe:

Good news is we can limit GitHub secrets to protected branches. There is a concept of environmental secrets on repository settings (Settings > Environments). It has a feature so you can you can limit the branches that can use environment secrets using Deployment branches. You can select protected branched or specific branches ex. main. This way the workflow action running on other branches cannot access your secret. Of course GitHub environment is meant for deployment, so if you are using it to protect your sensitive secrets for any things other than a deployment, you are doing a workaround!

Limit github secrets to protected branches

A disaster called github_token

The ‘GitHub Token’ is both good and evil; without it you would need a PAT token to do the simplest things (like checking out code on the runner) the problem is that it has too much power. For example you can use this workflow to impersonate your colleagues and push code on their name (much easier for a malicious piece of complicated code gets approved when it comes from your organization well known code hero!)

name: change and commit readme
on:
  workflow_dispatch:
permissions: 
  contents: write
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - shell : bash
        run : |
              echo " Add this to readme!!" >> README.md
              git config user.name YourFavoritUserName
              git config user.email [email protected]
              git commit -am "auto pushed by githubToken"
              git push

Code above adds a Add this to readme!! to readme of the main branch and commits it as any name. It might blow you mind to know it does it even if the user does not exist. You might think we protect our main branch so we are safe. Well, protecting the main branch saves us a lot of trouble, but you can still impersonate and commit to a feature branch.

Unfortunately, this is only the tip of the iceberg, github_token can do a lot more! For example, can make a new release with malicious code and it even don’t need to commit that. Here is all the access github_token has, and we are mostly worried about the write access. Fortunately, as you can see as long as we stick to the forking for contribution we are pretty much on the safe side.

ScopeDefault access
(permissive)
Default access
(restricted)
Maximum access
by forked repos
actionsread/writenoneread
checksread/writenoneread
contentsread/writereadread
deploymentsread/writenoneread
id-tokenread/writenoneread
issuesread/writenoneread
metadatareadreadread
packagesread/writenoneread
pull-requestsread/writenoneread
repository-projectsread/writenoneread
security-eventsread/writenoneread
statusesread/writenoneread
github_token permissions

But if you add people or teams as contributors with write access to your repository (manage access), you should be aware of the risk you are introducing.

Summery

Generally GitHub is very safe, don’t get men wrong. And for most cases these security problems are not a bit deal, specially the open source and smaller organizations. But as we sow both GitHub secrets and github_token has security flaws. While GitHub secret is reservable using workflow on any branch you can use environmental secrets to limit the sensitive information to protected branches workflows. Also, GitHub Token has too much power and can make unwanted changes so a bad person that can make workflows on your GitHub repository can make changes to your code or your release packages and artifacts using that token.


Posted

in

,

by

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *