Security & Signing
Verified Commits & Secrets
Why it matters
Anyone can set git config user.name to ‘Linus Torvalds’. Signed commits prove identity cryptographically. And leaked secrets in Git history are a nightmare.
Key concepts
- Signed Commits — Cryptographically prove commit authorship
- GPG — GNU Privacy Guard—encryption and signing tool
- git-secrets — Tool to prevent committing secrets
- Verified Badge — GitHub indicator that commit signature is valid
The idea
The Identity Problem
Git’s user.name and user.email are just text—anyone can fake them:
git config user.name "Elon Musk"
git config user.email "elon@tesla.com"
git commit -m "Fire everyone"
This commit would look like it came from Elon. Scary, right?
Signed commits solve this. They use cryptographic signatures that can only be created with your private key. GitHub shows a “Verified” badge on signed commits.
The Secrets Problem
Git remembers everything. If you commit an API key and then delete it, the key is still in history. Forever. Anyone who clones can find it.
# This shows ALL content ever committed
git log -p --all | grep "API_KEY"
Prevention is the only real solution—once secrets are in history, you need to rewrite history (painful) or rotate the credentials (essential).
Walkthrough
GPG Signed Commits
Setup GPG Key
# Generate key pair
gpg --full-generate-key
# Choose: RSA and RSA, 4096 bits, no expiration
# List keys (get the KEY_ID)
gpg --list-secret-keys --keyid-format=long
# Output: sec rsa4096/KEY_ID 2024-01-01 [SC]
# Export public key (add to GitHub)
gpg --armor --export KEY_ID
# Configure Git
git config --global user.signingkey KEY_ID
git config --global commit.gpgsign true # Sign all commits
Signing Commits
# Sign a single commit
git commit -S -m "Signed commit"
# Verify signatures
git log --show-signature
# Verify specific commit
git verify-commit abc123
SSH Signed Commits (Git 2.34+)
# Configure SSH signing
git config --global gpg.format ssh
git config --global user.signingkey ~/.ssh/id_ed25519.pub
# Sign commits (same as GPG)
git commit -S -m "SSH signed commit"
Protecting Secrets
Prevention: .gitignore
# Environment files
.env
.env.local
.env.*.local
# Credentials
*.pem
*.key
credentials.json
secrets.yaml
# IDE with potential secrets
.idea/
.vscode/settings.json
Prevention: git-secrets
# Install
brew install git-secrets # macOS
# or build from source
# Initialize in repo
git secrets --install
# Add AWS patterns
git secrets --register-aws
# Add custom patterns
git secrets --add 'password\s*=\s*.+'
git secrets --add --allowed 'password = "example"'
# Scan history
git secrets --scan-history
Prevention: Pre-commit Hooks
# .pre-commit-config.yaml
repos:
- repo: https://github.com/gitleaks/gitleaks
rev: v8.18.0
hooks:
- id: gitleaks
Response: If Secrets Are Leaked
# 1. Immediately rotate the credential!
# This is the most important step.
# 2. Remove from history (if necessary)
# Use BFG Repo-Cleaner (faster than filter-branch)
bfg --replace-text secrets.txt repo.git
# 3. Force push (coordinate with team)
git push --force --all
# 4. Notify affected parties
GitHub Security Features
| Feature | Purpose |
|---|---|
| Secret scanning | Alerts on committed secrets |
| Dependabot | Security updates for dependencies |
| Code scanning | SAST analysis |
| Branch protection | Require signed commits |
| Verified badge | Shows commit is signed |
Key takeaways
- Signed commits prove identity cryptographically
- GPG or SSH keys can sign commits
- Once secrets are in history, they’re there forever
- Prevention > cure: use .gitignore and pre-commit hooks
Dos & don’ts
✅ DO
- Sign commits on important projects: Open source, corporate
- Use git-secrets or gitleaks: Prevent accidents
- Rotate leaked credentials immediately: Don’t just delete from repo
- Enable GitHub secret scanning: Free protection
- Add .env to .gitignore before first commit: Prevention is easier
❌ DON’T
- Don’t commit secrets, ever: Not even “temporarily”
- Don’t rely on .gitignore after commit: It’s too late
- Don’t share GPG private keys: One key per person
- Don’t ignore secret scanning alerts: They’re real problems
Going deeper
Requiring signed commits: GitHub branch protection can require all commits to be signed. Settings > Branches > Branch protection > Require signed commits.
Vigilant mode: GitHub can mark unsigned commits as “Unverified” rather than just not showing a badge. Helps identify potentially spoofed commits.
Rewriting history: BFG Repo-Cleaner is 10-100x faster than git filter-branch for removing secrets. But it requires force-push and coordination—everyone must re-clone.
Common mistakes
Deleting secret doesn’t remove it:
git rm .env && git commit leaves .env in history.
You need to rewrite history with BFG or filter-branch.
GPG key expiration: If your GPG key expires, old commits still show as verified. But you can’t make new signed commits until you extend or replace the key.