May 30, 20180 mins read
In the second installment of our cheat sheet series, we’re going to cover how you can be more secure as a GitHub user or contributor. Much of it is specific to GitHub best practices, but there’s also general advice in both the cheat sheet and this blog that is applicable to other source code repositories. You can download the GitHub Security Cheat Sheet here. In case you missed our first cheat sheet on the dos and don’ts of Java type inference introduced in Java 10, make sure you check that out as well.
So let’s get started with our list of 10 GitHub security best practices, starting with the classic mistake of people adding their passwords into their GitHub repositories!
1. Never store credentials as code/config in GitHub.
There are a bunch of great tools available, like git-secrets, that can statically analyse your commits, via a pre-commit Git Hook to ensure you’re not trying to push any passwords or sensitive information into your GitHub repository. Commits will be rejected if the tool matches any configured regular expression patterns that are designed to find sensitive information. It may slow down pushes a tiny bit, but it’s well worth it.
You can also use tools like git-secrets in your CI and CD pipelines to actively break builds when sensitive information is found in code or a config file. Having team-wide rules that prevent this from happening is a great way to police bad actions in the existing developer workflow. A preferred way to hold or pass sensitive information is through the environment variables of the chosen CI/CD pipeline tools you are using, such as Jenkins or TeamCity. You can also use a tool like Vault to help with your secret management in production. Lastly, consider using an identity and user management tool chain, like Keycloak (currently maintained by a number of developers in Red Hat) as well as others.
There are many ways to avoid putting credentials into your repository in the first place, and you should try to implement as many as you can, but there’s always the chance some sensitive information may sneak in. You should also consider regular auditing of your repos, making use of tools like GitRob or truffleHog, both of which scan through your codebase, searching for sensitive information via pattern matching.
2. Remove Sensitive data in your files and GitHub history
If you find sensitive data in your GitHub repository, you need to do a number of things to recover. First of all you’ll need to invalidate the tokens and passwords that were once public. Once a secret is public on the internet, you should assume it’s in the hands of attackers and react accordingly.
Of course, you’ll also need to remove the sensitive data from your repository, but don’t forget that GitHub is very good at keeping a full history of all your commits. This includes changelogs that will list your sensitive information. It’s important you clear your GitHub history when you remove sensitive data from a repo. For more info, see purging files from your repository’s history.
3. Tightly Control Access
Here in the UK, when it gets really, really hot (read as, mildly warm) us Brits tend to open all the windows in the house to make sure that it doesn’t turn into a sauna. However when we leave our houses, we’ll double lock the front door, often leaving many of the windows partially open to keep the airflow moving. Of course this makes no sense, as anyone wanting to break in won’t try to break in through the front door! They’ll look for an easier way in, perhaps by climbing through one of the conveniently opened windows. We often take the same approach to securing our applications. We can focus very hard on the more complex attack vectors, but fail miserably against some of the simplest.
For instance, it only takes one developer to leave their password on a sticky note, hanging off their monitor for an attacker to gain access. We must ensure our basic settings and practices, both on the GitHub platform as well as in general, are adhered to. Mandate the following basic practices for your contributors:
Require 2-factor-authentication on every contributor’s GitHub account.
Never let users share GitHub accounts/passwords.
Any laptops/devices with access to your source code must be properly secured.
Repository administrators should manage team access to data. Only give contributors access to the data they need to do their work.
GitHub accounts are often personal ones, and do not naturally disappear when users leave the company. Make sure you diligently revoke access from users who are no longer working with you.
4. Add a SECURITY.md file
It’s natural for most project owners and maintainers to add a README.md for their repository. In fact, these days it’s quite frowned upon if one is missing. Likewise, it’s becoming increasingly common to add a SECURITY.md file that highlights security related information for your project. Not only does it give users the important security information they need, but it also forces the maintainers to think about how they should deal with security disclosures, updates and general security practices.
Here’s a high level overview of some of the suggested topics that you should cover in the SECURITY.md file:
The 2020 Snyk State of Open Source Security report shows that only 21% of respondents check for responsible disclosure policy. Meanwhile it is critical to define the procedure of how an issue reporter can fully disclose security issues responsibly. This should include who to contact and how. This is extremely important as it allows you to gain important feedback from your users.
People are lazy in general and if there’s no easy of well defined way of doing something, it’s easy for us to not bother doing it at all. Others may log the existence of a vulnerability as an open issue, inadvertently making the world aware of it before a fix is available. Make sure you give your users all the direction they need to give the right information to project maintainers when issues are found.
Security Update policy.
Software vulnerabilities are discovered every single day. When a vulnerability is found in your application or library, you have a responsibility to your users to tell them about it. They could be using your open source code in production on critical systems. You need to have a well defined process to share the relevant information with them, including the severity of the vulnerability, the risk it brings, and how to move to a fixed version of your code.
Define this process upfront so that the information is pushed to your users, allowing them to be updated as early as possible about new security vulnerabilities as they are found and fixed.
In 2020 Snyk discovered a prototype pollution in Lodash. At the time, the popular npm library was used by 4.35 million projects on GitHub alone. The project had just shy of 40k GitHub project stars, and the library had been downloaded over 80 million times each month. The team proactively opened thousands of automatic fix pull requests for its users to remediate the vulnerability.
A SECURITY.md file is a good home for such info on the repo, and if you have a website, consider an independent page for it - see Express.js’s security page as an example.
Security related configuration.
The security considerations of your project go beyond your code alone. Users will likely need to configure your project and create settings in order for it to work as they need in their environment. You should provide your users with suggested settings to consider that will harden their security posture when deploying this project.
Examples include turning on HTTPS, adding an authorisation layer and of course replacing default passwords (guidance many MongoDB users wish they’ve gotten). Remember that users typically have a fairly low understanding of security, so any advice you can pass on will help them greatly.
Known security gaps & future enhancements.
Very rarely are projects in such a state that all the security improvements you want to make have been implemented. It’s important to inform users of the security controls that aren’t currently in place. Your users deserve to know the full story so they can make informed decisions about how they use your project. Who knows - you may even get contributions from your users of a security control implementation on the list!
There’s a tradeoff between giving your users the information they need to secure their environment versus enabling an attacker with suggested attack routes. Always consider how the information you share could be used by both parties.
5. Validate your GitHub Applications Carefully
All good platforms can be extended, and GitHub with its application marketplace is no exception. Applications are written by organisations and third party developers, so keep this in mind when adding them to your repository. Consider the following when selecting and installing GitHub applications:
Don’t give applications more access rights than they need.
Question why an application requires the level of access it asks for, and think about the damage it might cause with that level of access.
Validate that the author or organisation behind the application are legitimate and have credibility before giving them access to your repositories, the same as you would bringing in a new committer.
You’re only as secure as your weakest link, so if an application you’re giving access to has a poor security posture, a breach of their code will give attackers access to your code - one of your most sensitive assets.
Lastly, make sure you monitor or audit your applications and their contributors at regular intervals to ensure you still need them, still trust them, and still deem them worthy of the access they require.
6. Add Security Testing to PRs
GitHub has a powerful event driven Git Hook framework that allows you to send HTTP POST requests to a service of your choice when events are fired. There are a vast number of events you can choose to act upon, but one of the most useful for testing your incremental code changes is the pull_request event. There are many static code analysis tools that support Git Hooks such that when a PR is created, an HTTP POST is fired to prompt them to test your latest updates. This is a great point in time to ensure that code and config changes being made are aligned with your security expectations.
Let’s use Snyk as an example (a bit of a shameless plug, but a good example nonetheless). Snyk statically analyzes your repo to find vulnerable dependencies you may be using and helps you fix them. You can test your repos through Snyk’s UI to find issues, but also to keep users from adding new vulnerable libraries by testing pull requests and failing the test if a new vulnerability was introduced.
Beyond the convenient integration into GitHub, pull requests are better than “breaking the build” in the fact they don’t have to block a merge (in fact, they’re informational by default), and their ability to test your changes, not just the outcome (e.g. fail only if you introduced a vulnerable library, not if there was one there already).
7. Use the Right GitHub Offering for your Security Needs
Depending on your project or organisational regulations, you may be restricted to software that can only run locally. Or perhaps the restrictions are on where your source code is stored or which other organisations can have access to it. This is a common restriction for financial institutions, government departments or other tightly regulated industries. However this doesn’t mean that you can’t use GitHub!
Take a look at the fully on-prem GitHub Enterprise offering, which allows you to fully host GitHub repositories within your organisation. This means your can be disconnected from the internet and still have internal access to your projects within your GitHub Enterprise repositories. Not even GitHub have access to your codebase!
8. Rotate SSH keys and Personal Access Tokens
GitHub access is typically done using SSH keys or personal user tokens (in lieu of a password, because you enabled 2FA!). But what happens if those tokens are stolen and you didn’t know? Be sure to refresh your keys and tokens periodically, mitigating any damage caused by keys that leaked out.
9. Create New Projects with Security in Mind
When creating a new project, developers are often happy to hack around and take short cuts just to get an application up and running. This might lead to developers becoming sloppy with sensitive information like passwords which might be hard coded, or stored locally in config, like a properties file. Less blatant security secrets include relying on a secret algorithm to authorise input, or exposing how you seed random numbers It’s a good practice, even for a closed source project, to develop it with an open source mindset. You’ll more likely write better code that is more secure if you consider you’re writing code that others will see and potentially exploit.
In addition, if you ever do think that you’ll want to open source the code it will be a lot easier and safer as you were already thinking in the more secure open mindset, so there’s less change you’ll miss a password or key that you hid in the code.
10. Audit any Code you Import into GitHub
This leads us nicely into what you need to do when you import projects or large chunks of code into GitHub. Source code that you import into GitHub may have existed for months or years, and possibly been developed in a closed source repository. This can lead to many of the once reasonable assumptions made in a closed source environment now being invalid. Always ensure you do a complete audit before you import anything into GitHub. This might be a trivial exercise for smaller projects, but once your codebase reaches a certain size, it can take teams many weeks or months to fully audit, update and pull in to an open source repository.
For further reading on GitHub security best practices, make sure you also read the GitHub security documentation and the GitHub business security site for additional features such as external auth/SAML support. And if you haven’t done so yet, make sure you download the cheat sheet now and pin it up, so your future decisions are secure decisions!