Skip to main content

10 GitHub Security Best Practices

Written by:
blog-feature-open-source-security

February 5, 2024

0 mins read

Editor's note: February 5, 2024

The security landscape is constantly changing. As such, this blog has been updated to reflect the risks developers and security teams face today and how to overcome them.

In our rapidly advancing, code-dominated digital landscape, safeguarding your codebase takes center stage. GitHub is the go-to platform for code sharing and version control in the developer community. However, given its widespread adoption, GitHub is not immune to many of the security challenges that developers face daily. From unauthorized access to the risk of sensitive data leaks, it's vital for developers to involve themselves in GitHub security best practices to harden their code and development workflows.

In this cheat sheet, we will discuss ten best practices you can implement to improve your GitHub security. Download the one-pager and read on for a more extensive explanation of all ten curated actions.

Enable and enforce 2FA for GitHub

Two-factor authentication, often abbreviated as 2FA, is a security protocol that requires users to provide two different authentication factors to verify their identity. Typically, this involves something you know (like a password) and something you have (like a phone). This multi-layered approach makes it significantly harder for an unauthorized person to access your data — which is a crucial tool in AppSec and code security.

GitHub is a treasure trove of intellectual property and sensitive code. As developers and DevOps professionals, the security of our code repositories and integrity of the open source projects we work on are of the utmost importance. 2FA provides that additional layer of security, making it harder for potential attackers to gain unauthorized access even if they manage to get hold of your password.

To enable 2FA on GitHub, follow these simple steps:

  1. Log into your GitHub account.

  2. Click on your profile picture in the upper-right corner, then click on Settings.

  3. In the sidebar, click on Security.

  4. Click on the Enable two-factor authentication button.

  5. Choose whether you want to use an authentication app or receive text messages for your 2FA, and follow the prompts to set up.

  6. Finally, you'll be given some recovery codes. These are important if you lose access to your 2FA method, so make sure to save them somewhere secure.

Making two-factor authentication (2FA) mandatory for your organization's GitHub repositories is a crucial step in enhancing security. By requiring 2FA, every team member accessing the repository must provide an additional layer of verification, such as a temporary code from an authentication app or via SMS. This extra security measure significantly reduces the risk of unauthorized access, especially in the case of compromised passwords. Enforcing mandatory 2FA secures your codebase and demonstrates a proactive commitment to maintaining a safe development environment, aligning with best practices for robust access control.

Limit access to repositories

In the world of application security and code security, limiting access to your GitHub repositories is essential. It’s an efficient way of managing who can view, edit, or administer your source code. This practice not only helps in maintaining the integrity of the code but also safeguards it from potential security threats. 

The principle of least privilege (PoLP) is a computer security concept in which a user is given the minimum levels of access necessary to complete their job functions. This principle should also be applied to your GitHub repositories.

Applying PoLP to your repositories helps in mitigating risks associated with:

  • Accidental exposure of sensitive data: Restricting access minimizes the chances of sensitive data being accidentally pushed to a repository, as fewer people have write access.

  • Malicious attacks: By limiting access to your codebase, you reduce the number of entry points for potential attackers.

  • Unintended changes: Fewer people with write or admin access means fewer chances of unintentional code alterations that can lead to bugs or broken builds.

GitHub provides several user access levels for repositories — Read, Triage, Write, Maintain, and Admin. Each of these access levels offers different capabilities to the user. For instance, a user with Read permissions can only view and fork the repository, while a user with Admin permissions can manage the repository's settings, teams, and integrations.

blog-github-best-practices-permissions

Remember, always give the least amount of access necessary for a collaborator to perform their role. You can always increase their access level later if needed.

Prevent storing credentials as code/config in GitHub

Storing credentials directly in GitHub repositories poses a significant security risk by exposing sensitive information to potential unauthorized access. To mitigate this risk, developers should adopt secure alternatives to store sensitive information, such as utilizing environment variables or configuration files outside the version-controlled repository. By referencing these external variables or files in the code instead of hardcoding credentials, developers maintain a clear separation between sensitive data and the publicly accessible codebase, reducing the risk of inadvertent exposure.

During development, Snyk Code can help identify hardcoded credentials and secrets in the code while developing. The Snyk Code IDE plugin is a great tool for catching potential security issues before the code is committed.

blog-github-best-practices-hardcoded-creds

Additionally, specialized tools like GitLeaks and Git-secrets are essential in enhancing security. GitLeaks scans repositories for secrets and API keys, providing immediate alerts when compromising information is detected. Integrating GitLeaks into CI/CD pipelines or pre-commit hooks enables swift remediation. Git-secrets, another valuable tool, prevents the accidental inclusion of secrets by scanning commits, branches, and staged files for predefined patterns of sensitive data. Configured to deny commits with identified patterns, Git-secrets acts as a robust defense against inadvertent leaks, reinforcing security measures in Git and GitHub repositories.

Combining these tools with your development workflow enhances the proactive identification and mitigation of security risks associated with storing credentials in Git and GitHub repositories. Through regular scans and automated checks, teams can significantly reduce the likelihood of exposing sensitive information, fortifying their codebase against potential security threats.

If a secret is detected, promptly assess and identify affected areas within the repository. Remove or replace compromised credentials, rotate associated keys or passwords, and inform team members about the incident. In addition, you can consider removing the sensitive data by rewriting the git history with a tool like BFG Repo-Cleaner if invalidating or replacing it is insufficient. Keep in mind that this history can be copied onto local machines or in the forks of your repo.

Connect your repositories to Snyk and scan for vulnerabilities


One of the best AppSec and code security practices is to connect your GitHub repositories to Snyk, a leading developer-security tool. This integration enables you to automatically scan for vulnerabilities in your codebase, container images, open source dependencies, and infrastructure as code configurations.

Connecting your GitHub repository to your Snyk account is a straightforward process. First, sign in to your Snyk account and navigate to the Integrations page. Click on the GitHub integration and follow the steps to authorize Snyk to access your GitHub repositories.

Out of the box, Snyk offers four types of scans for your GitHub repositories:

  1. Snyk Open Source: This scan checks your open source dependencies for known vulnerabilities. It's an essential tool in open source security, as it helps you find and fix issues in your third-party packages. Snyk also has the ability to check the licenses for the dependencies used, helping you make the correct license compliance decisions.

  2. Snyk Code: This scan checks your codebase for security vulnerabilities and code quality issues. It helps in application security by identifying potential security flaws in your code. 

  3. Snyk Container: This scan checks your Docker container images for vulnerabilities. This is a crucial part of container security, as it ensures that your Docker images are safe to deploy.

  4. Snyk Iac: This scan checks your infrastructure as code configurations. It offers continuous monitoring and remediation to identify and fix vulnerabilities in cloud infrastructure configurations like Kubernetes, Terraform, CloudFormation, and more. 

blog-github-best-practices-javagoof

Scanning incoming pull requests

In addition to connecting your GitHub repositories to Snyk for comprehensive vulnerability scans, it's crucial to leverage the platform's ability to scan new pull requests (PRs) in real-time. Snyk's pull request scanning feature allows you to proactively identify and address security vulnerabilities introduced during the development phase. As developers propose changes in their PRs, Snyk automatically scans the modified codebase, open source dependencies, and container images, highlighting potential vulnerabilities before the code is merged into the default branch.

This proactive approach empowers development teams to remediate security issues at the early stages of the development lifecycle, reducing the risk of introducing vulnerabilities into the production environment.

By seamlessly integrating Snyk into your GitHub workflow, you enhance the security of your codebase and foster a DevSecOps culture that prioritizes continuous security throughout the software development process. Connecting your repositories to Snyk and enabling pull request scanning adds an additional layer of defense, ensuring that only secure code is merged into your default branch.

Add a SECURITY.md file

Alongside the essential README.md file, the integration of a SECURITY.md file is a crucial step in elevating the security posture of your project. This dedicated file acts as a centralized hub for critical security information, ensuring transparency and offering clear directives to contributors and stakeholders.

Disclosure policy

Establish a clear procedure for individuals discovering security issues, designating a contact point, often configured as the “security@” email. This policy fosters responsible disclosure, enabling external parties to securely report security concerns and encouraging a collaborative approach to managing vulnerabilities.

Security update policy

Outline how the project plans to disseminate information about newly identified security vulnerabilities. This encompasses the channels through which users will receive notifications and the steps they should take to promptly address these issues. A well-defined update policy ensures users stay informed and can take necessary actions to secure their deployments.

Security-related configuration

Highlight settings that users should consider to impact the security posture when deploying the project. This section serves as a practical guide for configuring security measures, ensuring users are well-informed about the choices they can make to enhance the overall security of their deployments.

Known security gaps and future enhancements

Transparently communicate any existing security gaps that are recognized but not yet addressed. Additionally, share insights into future security enhancements that are in consideration but haven't been implemented. This cultivates a culture of transparency and collaboration, encouraging contributors to actively participate in improving the project's security.

The SECURITY.md file plays a pivotal role in establishing a secure and open environment for your project. It not only sets the groundwork for responsible security practices but also serves as a valuable resource for contributors and users, ultimately contributing to a more resilient and secure project ecosystem.

Use branch protection rules

Branch protection rules provide an essential layer of security in a DevSecOps workflow, preventing unauthorized or accidental changes to sensitive parts of your codebase. In this section, we will explore what branch protection rules are and how you can set them up in GitHub to enhance the security of your codebase.

Branch protection rules in GitHub are a set of controls that repository admins can set to enforce code quality and manage collaboration. They give you the ability to configure and enforce exactly how code changes should be merged into a branch. This is a critical aspect of application security and code security as it enforces the principle of least privilege, ensuring that only authorized users can make changes to the codebase.

Some of the controls that you can enforce with branch protection rules include:

  • Require pull request reviews before merging: This ensures that at least one other person reviews and approves the changes before they can be merged into a protected branch.

  • Require status checks to pass before merging: This can be used to ensure that all required CI tests pass before the code can be merged.

  • Restrict who can push to matching branches: This allows you to specify which users or teams can push to a protected branch and 

  • Enforce a linear commit history: This ensures that the commit history is clean and easy to understand.

Steps to set up branch protection rules

To set up branch protection rules in GitHub, follow the steps below:

  1. Navigate to your GitHub repository, and go to the Settings tab.

  2. In the left sidebar, click Branches.

  3. Under Branch protection rules, click Add rule.

  4. In the Branch name pattern field, enter the name of the branch you want to protect.

  5. Under Protect matching branches, select the requirements you want to enforce. You can choose from the options mentioned above.

  6. Click Create to save your new branch protection rule.

Using branch protection rules effectively can significantly improve the security and reliability of your codebase. For most repositories used within Snyk, you cannot directly push to the main branch for security reasons, and are forced to use a PR. This is enforced by implementing branch protection rules.

Rotate SSH tokens and personal keys

Regularly rotating SSH tokens and personal keys is an essential practice to boost code security in your GitHub repositories. This section will guide you on how to achieve that and why it matters in the realms of application security, container security, and DevSecOps.

Rotating SSH tokens and personal keys is a proactive security measure that helps prevent unauthorized access to your GitHub repositories. If a malicious actor somehow gets hold of your SSH token or personal keys, they can wreak havoc in your codebase. Regular rotation of these credentials makes it hard for attackers to maintain access to your repositories, enhancing your open source security.

How to rotate SSH tokens and personal keys

GitHub facilitates the rotation of SSH tokens and personal keys with a straightforward process. Here are the steps:

  1. Log into your GitHub account.

  2. Navigate to Settings, Developer settings, then Personal access tokens.

  3. Click on Generate new token.

  4. Give your token a description and select the scopes (or permissions) that you want to grant to this token.

  5. Click on Generate token.

After generating a new token, be sure to replace the old one in all places where it's used.

Automating token and key rotation

For teams with numerous repositories or large DevOps environments, manually rotating SSH tokens and keys can be a daunting task. Automating this process ensures consistency and saves time. You can leverage GitHub Actions or your CI/CD pipeline tools, like Jenkins, to automate the rotation process.

In conclusion, rotating SSH tokens and personal keys is a vital practice in maintaining security in your GitHub repositories. Remember, the goal is not to make your life harder but to ensure that your code is secure and free from unauthorized access.

Automatically update dependencies

Maintaining an up-to-date and secure codebase is paramount in application security, code security, container security, and DevSecOps. One key aspect of this is the regular updating of dependencies. Security vulnerabilities are often found in outdated third-party libraries. Therefore, it's important to have a strategy for automatically updating dependencies to minimize the risk of security breaches. In this section, we'll delve into the importance of updating third-party libraries and how to use tools like Snyk to automate this process.

Third-party libraries are an integral part of software development as they enable developers to avoid reinventing the wheel by reusing code written by others. However, these libraries can become a weak link in your security chain if not properly managed. They can become outdated and pose serious security risks if they contain vulnerabilities that haven't been patched in the latest versions.

Updating dependencies manually can be a daunting and time-consuming task, especially for large projects. This is where automation comes into play.

Automating dependency updates with Snyk

Snyk is a powerful tool that helps identify and fix vulnerabilities in your dependencies. In addition to its vulnerability scanning capabilities, Snyk can also automate the process of updating your dependencies.

When integrated with GitHub, Snyk scans your repositories for outdated dependencies and vulnerable library versions. It then opens pull requests (PRs) on GitHub with updates to these dependencies, allowing you to review and merge these updates in a streamlined manner.

After connecting GitHub to your Snyk account, make sure the Automatic dependency upgrade pull requests option is enabled in the Integration Settings at the Organization level or in the Project Settings.

blog-github-best-practices-automatic-prs

Now, Snyk will monitor your repositories and create PRs for outdated dependencies, making it easier for you to keep your codebase secure and up to date.

blog-github-best-practices-snyk-pr

In conclusion, automating dependency updates is a best practice that every developer and DevOps practitioner should adopt. It not only improves the security of your applications but also saves time and effort in the long run. By leveraging tools like Snyk, you can stay ahead of security vulnerabilities in third-party libraries and maintain a healthy, secure codebase.

Use private repositories for sensitive data

Understanding how to manage sensitive data on platforms like GitHub is essential. One of the easiest ways to protect sensitive data is to use private repositories. In this section, we'll discuss the difference between public and private repositories and when it's best to use private repositories.

GitHub provides two types of repositories — public and private:

  1. Public repositories: As the name suggests, these repositories are visible to everyone. Any GitHub user can view, clone, and fork a public repository. However, only collaborators of the repository can push changes. This openness fosters collaboration and open source development.

  2. Private repositories: Private repositories are only visible to the repository owner and collaborators they have explicitly added. Even if someone has the URL to a private repository, they won't be able to see the content without the necessary permissions.

When to use private repositories

While public repositories can be great for open source projects and collaborative development, they aren't suitable for sensitive data. Here's when you should consider using private repositories:

  1. Protecting Sensitive Data: If your codebase contains sensitive data like API keys, passwords, or any confidential information, it should be stored in a private repository. This ensures that only authorized collaborators have access to this data.

  2. Proprietary Code: If your codebase is proprietary and shouldn't be publicly accessible, a private repository is the way to go. This is often the case for business applications and premium software products.

  3. Development Stage: When your project is in the early stages of development and not ready for public viewing, it's best to keep it in a private repository. This allows you to control who has access to the project during its development phase.

Disable the creation of public repositories

To enhance security and safeguard sensitive information, organizations not requiring public repositories should consider disabling public access entirely. This proactive measure helps prevent the accidental creation of publicly accessible repositories, reducing the risk of data exposure. By enforcing private repository settings through the navigation path of Your Organizations, Settings, then Member Privileges, organizations ensure that repositories are exclusively accessible to authorized users. This not only aligns with best practices for data protection but also streamlines repository management, promoting a more secure and controlled environment for organizational code.

In conclusion, using private repositories for sensitive data is a crucial GitHub security best practice. It helps in safeguarding your sensitive data and proprietary code, thereby enhancing your code security and DevSecOps practices. 

Be smart about your GitHub apps

When it comes to GitHub apps, it's essential to make thoughtful choices. These applications, developed by various entities, offer great features, but before diving in, let's delve into some crucial considerations:

  • Permission Check: Resist the temptation to grant permissions liberally. Provide only what is absolutely necessary. Maintaining a streamlined access approach minimizes unwarranted risks.

  • Access Questions: When dealing with extensive access, rigorously question the necessity. Evaluate potential consequences if circumstances take an unfavorable turn. This is about measured risk.

  • Who’s Behind It: Before incorporating an app into your coding environment, conduct due diligence. Scrutinize the legitimacy of the creators. Consider this as vetting a new team member – trust is paramount.

  • Security Check: View an app's security as the frontline defense for your code. Any lapse here could render your code vulnerable. Scrutinize the security protocols to ensure a robust shield.

  • Keep Tabs Regularly: Regular housekeeping is indispensable. Periodically assess the continued necessity and trustworthiness of your apps. Think of this as upholding order in your code domain.

Remember, the security of your code is a solemn matter. Stay vigilant, make discerning choices, and uphold the stability and security of your application.

Conclusion

In conclusion, we've explored the pivotal role that GitHub plays in modern software development and the importance of implementing strong security best practices. The ten guidelines we've discussed provide a solid foundation for securing your GitHub repositories and projects. Each of these practices builds upon the other to create a robust defense against a variety of threats and vulnerabilities. 

To all developers and DevOps professionals, we urge you to take these security best practices to heart. Security is not just the responsibility of a single team or individual, but rather a collective commitment that permeates every aspect of software development and operations. 

As we often say in DevSecOps, "Everyone is responsible for security." Let's all play our part to ensure our applications, our data, and our users are as secure as possible. 

In the spirit of continuous learning, always remain open to new practices, tools, and processes that can further enhance the security of your GitHub environment. 

Happy coding, and stay secure!

Github_best_practices_cover_image

blog-feature-open-source-security

How CISOs are Transforming their DevSecOps Strategies

500 devs to 1 security professional is the reality of today. The security pro’s role must transform into an aware, knowledgeable, supportive partner capable of empowering developers to make security decisions.