Skip to content

gh auth login writes oauth_token to .config/gh/hosts.yaml even without passing --insecure-storage #7757

Closed

Description

@ryantm

I reported this issue via the GitHub HackerOne Bug Bounty program #2085800 and was told it was not a security vulnerability and that I should follow up with an issue here. Here is the original report:

Description:

On April 4th, version 2.26.0 of the gh GitHub CLI was released. The release notes (https://github.com/cli/cli/releases/tag/v2.26.0) say that a new field --insecure-storage was added to gh auth login, which should be the only way to opt-in to writing the oauth_token in cleartext to the disk at ~/.config/gh/hosts.yaml.

Due to the logic on this line

if !secureStorage || setErr != nil {
, a system that does not have a Keyring service configured, will fall back to using the cleartext storage without having specified --insecure-storage on the commandline.

Steps To Reproduce:

  1. confirm using gh past version 2.26.0 (I used 2.32.1)
  2. Use the Gnome desktop environment
  3. Open the Passwords and Keys application
  4. Ensure all keyrings are locked
  5. gh auth login on commandline
  6. When prompted to unlock the keyring, refuse to unlock
  7. Follow auth flow to web page and enter device code
  8. When prompted to unlock the keyring, refuse to unlock
  9. cat .config/gh/hosts.yml and observe the cleartext oauth_token entry is present

Not all environments have a keyring configured, and those environments will be more vulnerable because they do not have to refuse to unlock. For example, on Replit, my employer, there is an interactive container environment that does not have a Keyring service.

Recommended fix

Import the log package and above line 231 add the following code:

if secureStorage && setErr != nil {
  log.Fatalf("gh no longer supports writing secret credentials to a cleartext file by default. To securely store your credentials, unlock or fix your operating system's keyring. If you cannot use the keyring and fully understand the risks, you  may pass --insecure-storage to bypass this. error:", setErr)
}

Impact

If the attacker has local access to a computer's file system, they can use the oauth token to read a user's private GitHub repositories and write to all of the repositories they have access to. Additionally, they can do anything the gh cli can do.


Issue

If this is not actually a security vulnerability, then it is a UX issue, because the commandline help says

--insecure-storage      Save authentication credentials in plain text instead of credential store

which implies it will not insecurely store credentials without that flag.

The release note also says

We've added a new flag, --insecure-storage, to opt into the old insecure behavior in case you need to debug an issue with credential storage.

which also implies you need to use the new flag to opt into old insecure behavior, but you do not need to use that flag to opt into the behavior.

Activity

  1. samcoe commented on Jul 27, 2023

    @samcoe
    Contributor

    @ryantm Thanks for the feedback. I can understand how this fallback behavior can be confusing since it is not documented anywhere. We purposefully added the fallback to plaintext behavior as to not break gh for users who are on systems that are not supported by our keychain library. I do not see us changing this behavior as the same concern still exists today. Instead of the proposed fix of removing the fallback I think we should document that if a suitable keychain is not found or there is an issue using it we will fallback to writing the token to plain text and that the user can use gh auth status to see where the token is being stored. Perhaps even during gh auth login we can output a warning stating that the token was written to a plain text file.

  2. added
    enhancementa request to improve CLI
    and removed
    bugSomething isn't working
    on Jul 27, 2023
  3. added a commit that references this issue on Aug 1, 2023
    969a464
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions