How to Prevent GitHub Fraud Using GPG Signatures

This article is transcribed by SimpRead, original address spencerwoo.com

So a GPG Key is essential, don’t take chances! Quickly get GitHub to mark your commits with the verified checkmark.

Cause

This story begins with our school packing up the belongings of graduating students. At the end of June this year, the COVID-19 pandemic resurged in Beijing, which directly prevented our university graduates in Beijing from returning to campus. Their personal belongings had to be packed up and shipped home by the school staff. This caused a lot of dissatisfaction among classmates, and discussions quickly escalated on Weibo and Zhihu. Of course, this was a unified action across Beijing; not only were our school’s students unhappy, but students from other Beijing universities reported even worse handling, so we will refrain from commenting on the matter here. However, since the beginning, some “helpful” students not only responded and expressed opinions on Zhihu and other platforms, but also directly organized and recorded timelines on GitHub.

A directory, the repository and URL are omitted for now.

Am I Involved?

Why did this repository catch my attention? First, regarding packing up the belongings, my own college actually did a good job. Personally, my belongings were packed by a well-respected associate professor in my department and were well organized, so I never had major complaints or joined the Zhihu discussions or protests. These events occurred two months ago, but today a classmate who knows me brought this repository to my attention and privately asked why I had contributed to this repository.

Yes, a repository I had no knowledge of until yesterday showed a “commit by my email,” which was “linked to my GitHub account.”

My reaction at that moment:

Curious, I clicked the link my classmate sent and scrolled down to Contributors. Sure enough, my avatar was right there.

Damn, I just found out about this repository yesterday; you’re really something.

Well, besides my avatar, there was another very familiar avatar — the following elderly gentleman:

This person looks vaguely familiar…

Hey, isn’t this the father of Python?! So the Python creator actually cares about our small university graduates packing their belongings?

I Was Surprised

Looking closely at the contributor list, there were many well-known figures in the open-source world, including some of my schoolmates who have GitHub accounts. Well, this repository, which seemed suspicious everywhere, appeared to have all commit author identities forged, except for the owner’s commits.

Modifying the details, what a joke; here, “my” commits were all altered to identified top classmates I know.

Yesterday, I was truly shocked: Git commit records can be forged. I had never considered such security issues before, assuming that commits always had proper identity verification, but the reality proved I was too naive.

To the unknown classmate: I don’t know your intention using our identities to alter the commit records in this “troublemaking” repository without our knowledge, but I find your behavior very disgusting. If you yourself are unwilling to bear the risks that come with “stirring things up,” and must forcibly drag along a group of uninformed classmates to make it seem like many people are involved, eager to contribute, then what are you even doing?!

So… what now? I have already emailed GitHub Support, but I don’t know if they will help resolve this. From my side, besides trying to notify the classmates who might be impersonated on GitHub, I can only analyze why this vulnerability exists and propose how to solve it moving forward.

Vulnerability Analysis

Git’s Design Flaw

In fact, Git inherently has this design flaw. The author information in a Git commit is a string that can be forged without cost. First, let’s look at what information each commit contains. We can use git log (or the Oh My Zsh alias command glog for a clearer commit history) to view the commit records in a local Git repository and find a specific commit hash, for example, my current repo HEAD commit hash is d3f97ef.

Git commit history in the repository.

Using a commit hash from last week, df6eb5f, we can run git cat-file -p df6eb5f to view detailed information of this commit:

Detailed info of commit hash df6eb5f.

We observe each commit has an author and a committer — the original author and the person performing the commit operation. How does Git confirm their identity? Git only records the names, emails, and timestamps for both the author and committer, which are set when we configure Git’s user.name and user.email. GitHub also relies on these two pieces of information to identify the commit’s author and the associated GitHub identity.

Now that we know how Git and GitHub identify authorship, how do we change author and committer info? These are just stored as strings; both user.name and user.email can be arbitrarily modified, so we can simply change our git config’s user.name and user.email to make a commit appear as if authored by someone else. Native Git has no second-level protection!

Furthermore, we can batch replace the entire repository’s Git commit history using filter-branch to impersonate others:

git commit -am "Destroy production"
git filter-branch --env-filter \
  'if [ "$GIT_AUTHOR_EMAIL" = "iamthe@evilguy.com" ]; then
     GIT_AUTHOR_EMAIL="unsuspecting@victim.com";
     GIT_AUTHOR_;
     GIT_COMMITTER_EMAIL=$GIT_AUTHOR_EMAIL;
     GIT_COMMITTER_; fi' -- --all
git push -f


Basically, Git commits can be modified arbitrarily—one can frame another person for a bad commit or bulk assign blame to unaware people for malicious commits. But I sincerely hope no one ever does such things!

How to Prevent This?

What can we do? How do we prove our identity online? How do we prove a commit is not from us? For Git, there is actually a way — GPG signing. GPG stands for GNU Privacy Guard and uses asymmetric encryption to prove “I am who I am” from a cryptographic perspective, also proving “this may not be me.”

By signing our commits with a GPG private key that only we hold, GitHub can verify that the commit is genuinely performed by us. This prevents malicious others from creating “signed” commits impersonating us. The GPG key used on GitHub is different from our SSH key; the latter is solely for proving identity to GitHub for pushing to repositories we have permission to commit to. The GPG key proves “I own the authorship of this commit,” and only commits signed with a GPG private key will show the green Verified badge on GitHub:

A GPG signed commit shows the Verified mark on GitHub.

Using GPG Key to Prove Commit Authorship

Install GPG

First, install the GPG command-line tool. On Windows, you can install via scoop install gpg. Most Linux distributions already have GPG installed.

# Windows user install GPG
$ scoop install gpg


Use gpg --version to check your GPG installation and version, and note the home directory where GPG stores keys.

# Test GPG (Windows or Linux)
$ gpg --version

gpg (GnuPG) 2.2.19
libgcrypt 1.8.5
Copyright (C) 2019 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Home: /home/spencer/.gnupg
Supported algorithms:
Pubkey: RSA, ELG, DSA, ECDH, ECDSA, EDDSA
Cipher: IDEA, 3DES, CAST5, BLOWFISH, AES, AES192, AES256, TWOFISH,
        CAMELLIA128, CAMELLIA192, CAMELLIA256
Hash: SHA1, RIPEMD160, SHA256, SHA384, SHA512, SHA224
Compression: Uncompressed, ZIP, ZLIB, BZIP2


Generate Your GPG Key Pair

Next, generate a GPG key pair with the following command:

$ gpg --full-generate-key


  • For key type, choose the default RSA and DSA.
  • For key length, follow GitHub’s recommendation and choose 4096 bits.
  • For key expiration, set as needed; default is never expire.
  • For user ID and email, enter your usual username and the email address verified on GitHub.
  • Finally, set a secure passphrase for the key and be sure to remember it.

Now you have your first GPG key pair! Check the keys you have with:

$ gpg --list-secret-keys --keyid-format LONG

/home/spencer/.gnupg/pubring.kbx
--------------------------------
sec   rsa4096/24CD550268849CA0 2020-08-29 [SC]
      9433E1B6807DE7C15E20DC3B24CD550268849CA0
uid                 [ultimate] Spencer Woo (My GPG key) <my@email.com>
ssb   rsa4096/EB754D2B2409E9FE 2020-08-29 [E]


In the sec line, rsa4096/24CD550268849CA0 is your private key ID; here 24CD550268849CA0 is the GPG private key ID.

Tell Git Your GPG Key ID

After generating your GPG key and obtaining the private key ID, configure Git to use this GPG key for commit signing:

$ git config --global user.signingkey 24CD550268849CA0
$ git config --global commit.gpgsign true


With this configuration, Git will automatically sign your commits with the GPG private key. Confirm signing by running:

$ git log --show-signature

commit c407d4efc980cbee981da50d714a751999b19ddf (HEAD -> master)
gpg: Signature made Sun Aug 30 17:16:18 2020 CST
gpg:                using RSA key 9433E1B6807DE7C15E20DC3B24CD550268849CA0
gpg: Good signature from "Spencer Woo (My GPG key) <my@email.com>" [ultimate]
Author: spencerwooo <my@email.com>
Date:   Sun Aug 30 17:16:18 2020 +0800

    Signed by GPG


Also, viewing the commit details with git cat-file -p will show the GPG signature embedded in the commit.

$ git cat-file -p c407d4e


A signed commit contains the PGP signature.

If there are issues signing, it might be due to Git using a different GPG binary than the one used to generate your keys. Find the GPG executable path with which gpg, e.g., /usr/bin/gpg, and configure Git to use it:

$ git config --global gpg.program /usr/bin/gpg


Tell GitHub Your GPG Public Key

Finally, you need to tell GitHub your GPG public key. For the private key ID 24CD550268849CA0, export the public key with:

$ gpg --armor --export 24CD550268849CA0


Copy the output and paste it into GitHub at Settings » SSH and GPG keys » New GPG key, then save it. Afterward, you can enjoy the Verified badge for your commits on GitHub!

Summary

Using GPG not only proves ownership of each commit but also can be used analogously in cryptographic ways to prove ownership of GitHub accounts, domain names, Twitter accounts, and more. We can host our GPG public keys on GPG servers so others can verify signatures against their respective public keys. Keybase.io is a trusted database for public keys, recommended for hosting your GPG public keys.

In any case, you can pull and import my (Spencer Woo’s) GPG public key with this command:

$ curl https://keybase.io/spencerwoo/pgp_keys.asc | gpg --import


  • My Keybase address: keybase.io/spencerwoo
  • My Keybase public key: ASCtXMcCY0UpKPF6NpoLlwJT3xXsD5nzunxF2ei4gBRBkgo

Thank you for reading, and I hope no one ever experiences impersonation!