On November 09, 2022, GitHub released a new feature to its beta technical preview. The feature allows users to report security issues to open-source maintainers adding to the existing “Security Advisory” feature. Before jumping into the vulnerability, let’s get an idea of the Security Advisory feature, how it works, and what has changed. If you want to read about the vulnerability directly, scroll to Private forks, collaborators & Codespaces = Exploit section.
The Security Advisory feature allows maintainers to draft public advisory information about a reported vulnerability. Once created, maintainers can start working on a patch by creating a private fork of the repository.
A private fork created by a security advisory slightly differs from a regular fork/repository. For example, a private fork for security advisories disables issues, projects, and discussions by default.
advisory.build_workspace_repository(attributes.merge({
name: name,
private: true,
owner: owner,
parent: nil,
network: nil,
created_by_user_id: actor.id,
has_issues: false,
has_wiki: false,
has_downloads: false,
has_projects: false,
repository_license: repository.repository_license&.dup,
}))
This indicates that by default, some additional access controls are implemented in this type of fork because they are sensitive. Once the vulnerability is fixed, maintainers can open a private PR against the vulnerability repository to merge later.
With the November release, Security Advisory allows organizations to allow external users to report vulnerabilities to their public repository. The permission model has not change significantly with the new feature:
However some things have changed:
An external user who reports a vulnerability via Security Advisory gets added as a collaborator to the patch repository. Investigating further, the patch repository is in the same organization as the vulnerable repository. Initially, this is not much impact because an external collaborator to a single repository does not have much access. Especially in this case, features like issues, projects, downloads, and actions were disabled. However, Codespace was enabled for these repositories.
GitHub Codespace is a cloud-based development environment allowing developers to contribute and test their code quickly. This environment comes with all development features since it runs in an isolated virtual machine for all users. In addition, to make it safer and more accessible for developers to collaborate with organizations, GitHub introduced Codespace Secrets. Codespaces secrets allow users and organizations to securely store sensitive strings such as API keys, SSH key pairs, passwords, etc. Codespace secrets exist for three resources: Organization, Repository, and Personal.
Since organization secrets can be set up to be accessed by ALL private repositories, we decided to test and check if external users can access these. Theoretically, this is how we visioned the exploit would work:
We enabled vulnerability reporting in one of our public repositories to test this. Then we used an external account to file a test security issue. With the external account, we created a private fork and a Codespace for the associated fork.
Since the Codespace was created in the context of the vulnerable organization, the env command printed out environment variables for the Codespace. This included the secrets in plaintext format. To confirm our vulnerability, we made a “flag” secret available to all private repositories in our organization.
Getting access to organization secrets for any organization that uses the new beta feature was already a problematic security issue, however, we wanted to escalate this further.
One way to attempt this was to exploit it against the GitHub (https://github.com/github) organization itself. After going through some public GitHub repositories, we identified that Github Enterprise Importer (https://github.com/github/gh-gei) has the feature enabled. We created a test security issue and a private fork for it. We then created a Codespace for the private fork. This allowed us to access Organization Secrets for GitHub organization. With the access, we were able to read and extract organization secrets for GitHub such as GOPROXY_TOKEN . The disclosed token was GitHub user token for gh-containers-bot. Further exploring the API, we called https://api.github.com/user/repos, which lists all accessible repositories for the user. This gave us access to multiple internal repositories of GitHub with read and write privileges. Once the token validity and access was confirmed, we reported the security issue to GitHub.