A relatively unknown and underused feature of Git is the ability to cryptographically sign commits. It is an optional feature that provides a way for the author of a commit to prove ownership. It uses the author’s GPG key to leave a signature in the commit that can be checked later. If you’re a Keybase user, it’s pretty easy to use your Keybase GPG key to sign your Git commits. Then, once you’ve signed your commits, GitHub provides a nice interface for verifying commits have been signed and by whom.
This tutorial walks you though the process I took to set up Git commit signing with my Keybase GPG key. I went from not having a GPG key installed locally through to seeing my commits marked as Verified on GitHub.
Why should we sign Git commits?
A few days ago, I was at NDC Security and saw a talk by Phil Haack where he spoofed a “malicious” commit to look like it was made by Troy Hunt (who was also speaking). It may sound difficult, but it’s actually a very trivial process. Git will accept any name and email address as the commit author and so will GitHub. So if you set the author on the commit to be a valid email address, it will look like they made the commit. This is due to the distributed nature of Git, which allows anyone to push anyone else’s commits around. However, from a security point of view, it’s a problem.
Unfortunately, there isn’t a way to stop someone from spoofing a commit with your name and email. However, Git does support cryptographically signing commits using a GPG key. This allows GitHub to mark your commits as
Verified when it can match your verified email to your GPG key. This won’t stop someone trying to spoof your commits, but it will provide assurance of your real commits so they can be properly verified.
GitHub and Keybase
GitHub provides a settings page for setting your GPG key, however if you upload your raw GPG key from Keybase, it will likely contain a Keybase user reference:
[email protected]. This isn’t a live email address and therefore GitHub will be unable to verify it. It also won’t match the email address in your commits. As a result, we need to do a few more things to get everything working.
I tried looking through the Keybase options, but couldn’t find any default way to modify the key and add email addresses. This seems like an oversight to me, but my understanding of this is limited, so there may be a good reason. Ultimately, I needed to export my key from Keybase into GPG so I could modify it directly. It turns out that Git needed it in there anyway, so it all works out nicely.
Updating the GPG key
Before you begin, I’m assuming you have Keybase installed and working via command line, and you have a GPG key already in your Keybase account. I used Git Bash on Windows 10, because I find it easier than CMD or PowerShell, but can use your preferred terminal.
First, export your public and private keys from Keybase using the
keybase pgp command:
keybase pgp export > keybase-public.key keybase pgp export --secret > keybase-private.key
During the export process, Keybase will ask for your account password and prompt to set a new password for the private key file.
Next, you need to import the keys into GPG using the
gpg --allow-secret-key-import --import keybase-private.key gpg --import keybase-public.key
The import process will ask for the password you just assigned to your private key, for obvious reasons.
Modifying the key (adding a new user)
Now that you’ve imported the key into GPG, you need to modify the key to include your email address. This is done by invoking the
gpg --edit-key command, with a unique identifier for your key. I found using the
<username>@keybase.io address worked nicely.
gpg --edit-key <username>@keybase.io
This command will get you into the
gpg> prompt, and from there you need to run the
adduid command. It will prompt for your
Real name and
Email address (feel free to leave
gpg> adduid Real name: <your name> Email address: <your email> Comment: You selected this USER-ID: "<your name> <your email>" Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit?
Once you’ve provided your name and email, confirm using the
O and then
save to close the
The entire key updating process should look something like this. Note that since I had already added my personal email address prior to saving this log, it shows me adding my work email address as a third user onto the key.
$ gpg --edit-key [email protected] gpg (GnuPG) 2.2.13-unknown; Copyright (C) 2019 Free Software Foundation, Inc. This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Secret key is available. sec rsa4096/C1C4BEBF0442284B created: 2014-09-18 expires: 2024-09-15 usage: SCA trust: unknown validity: unknown ssb rsa4096/3A829C5805933134 created: 2014-09-18 expires: 2024-09-15 usage: E [ unknown] (1). Stephen Rees-Carter <[email protected]> [ unknown] (2) keybase.io/valorin <[email protected]> gpg> adduid Real name: Stephen Rees-Carter Email address: [email protected]*********.com Comment: You selected this USER-ID: "Stephen Rees-Carter <[email protected]*********.com>" Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? O sec rsa4096/C1C4BEBF0442284B created: 2014-09-18 expires: 2024-09-15 usage: SCA trust: unknown validity: unknown ssb rsa4096/3A829C5805933134 created: 2014-09-18 expires: 2024-09-15 usage: E [ unknown] (1) Stephen Rees-Carter <[email protected]> [ unknown] (2) keybase.io/valorin <[email protected]> [ unknown] (3). Stephen Rees-Carter <[email protected]*********.com> gpg> save
Once that’s done, you can push your updated key back into Keybase.
keybase pgp update
Adding the key into GitHub
The easiest way I found to get the public key is to go to your Keybase profile (i.e.
https://keybase.io/<username>) and click on the public key in the identity list. A dialog will appear which includes a text box containing your public key. Copy this into the clipboard.
Then go to
Settings > SSH and GPG keys in GitHub. Click the
New GPG Key button and paste your public key in.
The final piece of the puzzle is to tell your local
git command to sign the commits using your key. This can be set either per-repository, or globally across all repositories in your computer’s current user with the
Use the git config
user.signingkey option to specify the Key ID for git to use. You can get this from the GitHub GPG keys page if you’re unsure what it is. For example, mine is
You can also require Git to sign all commits with the
git config --global user.signingkey <Key ID> git config --global commit.gpgsign true
Note, you will need to add your key to any computer/login that you use for commits to be signed.
Now, when you make any commits, Git will attempt to sign them with your key. It may ask you to unlock your key if you haven’t used it recently.
Once you’ve set it everything up correctly, you will see the friendly green
Verified indicator next to your new commits in GitHub.
That’s basically it. 🙂
Any future commits you from that computer/user will be verified, proving you are the author. Signing git commits won’t stop spoofing, but it will provide assurance of your real commits so they can be properly verified. I think that’s all we can do in Git for now.