Recently I’ve started to add the OSSF scorecard action to my (action) repositories. This is a GitHub action that will run the OSSF scorecard checks against your repository to see if you are following best practices, like having a security policy, using a code scanning tool, etc. Using this badge can give your users a quick overview of the security of your repository. OSSF stands for ‘Open Source Security Foundation’ and is an initiative to improve the security of open source repositories.
The scorecard action will do three things (if you use the default settings):
- Analyze your repository for the checks
- Upload the results to the GitHub Security tab (using a SARIF file)
- Upload the results to the OSSF API (A web API that you can even host yourself) With the data uploaded to the OSSF API you can then retrieve a badge with your latest score and show that on your repository:
The action checks your repository against several checks and then calculates a score for each check on a scale of 0 to 10. Based on the risk for that check, the score is then multiplied with a weight. The final score is the average of all the weighted scores. The higher the score, the better.
Some of the checks that are executed are:
- Branch-Protection: Is branch protection enabled for the default branch?
- Are GitHub Action versions pinned to SHA hashes, following best practices?
- Is the repository using a code scanning tool? Note that this check currently only supports CodeQL and SonarCloud
- Is there a security policy defined?
- Is there a definition file for Dependabot?
Setting it up
Setting is up is as easy as going to the OSSF scorecard action repo and copy the workflow example. Add that to you a new workflow file in your repo and run it from the default branch (usually
main). After the first run, you can add a link to your README.md file to show the badge.
Code scanning alerts
The default workflow also uploads the check results as a SARIF file to the Code Scanning Alerts that you can find on the Security tab of your repository. Each check can give one or more results, so you will get an alert for each result. That way you can fix the issues one by one.
Even better is that most of these alerts will give you actionable suggestions on how to fix the issue. For example, the alert above will give you a link to the Step Security Application that can analyze your repository and give you a pull request with the changes to fix the issue. They focus on three things:
- Restrict permission for the GITHUB_TOKEN
- Add security agent for GitHub hosted runner (Ubuntu only)
- Pin actions to a full SHA hash
Restrict permission for the GITHUB_TOKEN
One of the best practices is to always indicate what permissions you want to allow for the GitHub token that will be used in your workflow. The default setting is to permissive: it is
write for everything in your repo. I’ve been advocating that people always make this read-only at the organization level.
Since you cannot see what the organization permissions are, it’s a best practice to always specify the rights. You can add it to the top of your workflow file:
<span class="na">permissions</span><span class="pi">:</span> <span class="s">read-all</span>
And now you can override it at the job level if you need to. For example, if you need to push to a branch, you can add
write to the
<span class="na">jobs</span><span class="pi">:</span>
<span class="na">build</span><span class="pi">:</span>
<span class="na">permissions</span><span class="pi">:</span>
<span class="na">contents</span><span class="pi">:</span> <span class="s">write</span>
<span class="na">runs-on</span><span class="pi">:</span> <span class="s">ubuntu-latest</span>
<span class="na">steps</span><span class="pi">:</span>
<span class="c1"># etc</span>
Add security agent for GitHub hosted runner (Ubuntu only)
This setting is something I want to look into more. It seems that you can add a security agent to your GitHub hosted runner (available only for Ubuntu). It’s an extra product from Step Security which is available for free. It will analyze the network traffic in the job and log that in their system. After a couple of runs they know what kind of traffic is to be expected, and then you can convert that to basically a firewall rule. Any violations will then be logged and blocked. This can give you a better perimeter defense (as by default all traffic is allowed).
Definitely something to look into more!
Pin actions to a full SHA hash
The last option is to pin your actions to a full SHA hash. This is a best practice that I’ve been advocating for a while. It’s a bit more work, but it will make sure that your workflow will not be affected by a malicious actor pushing a new version of an action. What I really like is that this setting will analyze your workflow file (either pasted in or just all workflows in your public repo) and then suggest the SHA hashes of the actions, by looking at their latest version! Even better, they store the latest version in the comment next to the SHA hash, so you can understand where the hash comes from. Even Dependabot understands that comment and will update it in their version update PRs!