Post

Unauthorized access to Codespace secrets in GitHub

Summary

We identified a security issue in GitHub’s Repository Security Advisory feature (https://docs.github.com/en/code-security/security-advisories/repository-security-advisories/about-repository-security-advisories) that allowed us to retrieve plaintext Codespace secrets of any organization including GitHub.

Description

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.

How does Security Advisory work?

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.

Security advisory demo

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.

1
2
3
4
5
6
7
8
9
10
11
12
13
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.

What is new in Security Advisory?

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:

  • Security advisory is private till publicly disclosed by the organization.
  • Only owners/maintainers can merge the patch.

However, some things have changed:

  • The external reporter gets added as a collaborator to the vulnerability report. External collaborators get limited permission:
    • Comment on the advisory.
    • Accept the advisory credit.
  • When a private fork is made, the external reporter gets automatically added as a collaborator to the repository. The external reporter can then help patch the vulnerability and open a PR for the maintainer to accept.

Private forks, collaborators & Codespaces = Exploit

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.

What is GitHub Codespace?

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.

  • Personal secrets are created by user themselves and are available in all Codespaces created by them. (pretty much private to the user themselves)
  • Repository Secrets are linked to specific repositories and can only be accessed by those repositories.
  • Organization Secrets are linked to the organization and can further be linked to specific repositories (multiple at the same time) or all public/private repositories.

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:

  1. An external user creates a vulnerability report
  2. The external user gets added to the vulnerability report as a collaborator automatically.
  3. The external reporter creates a private fork for the security patch without admin approval.
  4. Created private fork is in the affected organization
  5. External reporter uses codespace for the private fork and accesses the organization level secrets.

Confirming the Vulnerability

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.

Create codespace

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.

Pulling flag

Escalating Further - Accessing GitHub’s internal repositories

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.

Report Timeline

  1. December 30, 2022 - Vulnerability reported to GitHub via the security program.
  2. December 30, 2022 - GitHub confirms they received the report and starts reviewing it [the report].
  3. December 31, 2022 - We internally confirmed that the vulnerability was patched.
  4. January 02, 2023 - Vulnerability confirmed patched
  5. March 07, 2023 - GitHub concluded it’s full investigation and report was resolved.
This post is licensed under CC BY 4.0 by the author.