Summary
GitHub shows commits signed with GitHub’s key as unverified because the signature is issued by GitHub’s server-side automation, not your personal GPG key. This occurs when commits are created via Codespaces or GitHub’s web UI and signed with the GitHub-provided key. The trust model requires user-specific keys to be in your GitHub account settings. The fix is to either sign locally with your own GPG key and push via CLI, or add GitHub’s public key to your local GPG trust chain (though this is not recommended for personal verification).
Root Cause
The core issue is a mismatch between the signing identity and verification trust:
- GitHub’s Codespaces and web UI automatically sign commits using a shared GitHub key (
EMAIL=gpg-key@users.noreply.github.com) - Your GitHub account only has your personal GPG keys configured
- GitHub’s web interface does not trust server-generated signatures by default because they are not linked to your verified identity
- The GPG trust model requires the signing key to be either:
- Your personal key in your GitHub account settings
- A key you have explicitly trusted (not the case with GitHub’s ephemeral key)
Why This Happens in Real Systems
- Decentralized signing models: Git allows any key to sign commits, but verification depends on the recipient’s trust database
- Ephemeral environments: Codespaces use transient GPG keys for convenience, but these are not associated with user accounts
- Trust chain isolation: GitHub’s web UI and Codespaces operate in a separate trust domain from user-configured keys
- Security model: GitHub intentionally does not auto-trust its own automation keys to prevent impersonation
Real-World Impact
- Merge blocking: Pull requests with unverified commits may be blocked in strict repositories
- Code review friction: Reviewers cannot trust commit authenticity
- Compliance issues: Audit trails become unreliable when commits appear unverified
- Developer productivity: Engineers cannot use convenient workflows (Codespaces, web editing) while maintaining verified status
- Team trust: Unverified commits reduce confidence in commit attribution
Example or Code
If you need to sign commits locally with your own GPG key, use this workflow:
# Configure Git to use your personal GPG key
git config --global user.signingkey YOUR_KEY_ID
git config --global commit.gpgsign true
# Make a commit (will be signed with your key)
git commit -m "Fix: update API endpoint"
# Push to GitHub (verification will show as verified)
git push origin main
If you want GitHub to recognize commits made via Codespaces, you must:
- Add your personal GPG key to GitHub account settings
- Configure Codespaces to use your key:
# In Codespaces terminal git config --global user.signingkey YOUR_KEY_ID git config --global gpg.program gpg
How Senior Engineers Fix It
- Use local signing with personal keys: Configure Git to sign all commits locally and push via CLI
- Avoid server-side signing for verified status: Treat Codespaces/web UI as convenience, not for verified commits
- Document workflow: Create team guidelines specifying when to use Codespaces vs. local signing
- Use SSH keys as alternative: For some workflows, SSH signing can be configured (GitHub supports it)
- Pre-commit hooks: Set up hooks to ensure signing with correct key before commits leave local machine
- Key management: Use hardware security modules (YubiKey) for secure personal key storage
Why Juniors Miss It
- Assumption of automatic trust: Juniors expect GitHub to automatically trust its own system keys
- Lack of GPG model understanding: Don’t understand that verification is recipient-side, not sender-side
- UI vs. CLI confusion: GitHub’s web UI shows “signed” but not “verified”—the distinction is subtle
- Overreliance on convenience: Codespaces ease of use hides the signing mechanism details
- Incomplete documentation: GitHub docs mention verification but don’t clearly explain the key ownership requirement
- Missing context: Not aware that GitHub’s automation keys are intentionally untrusted for user commits