6dd2e6aec8be3a659183378b6e67ef390cf0c411
Add safety gate prompt to all interactive tmux scenarios, add new "safety gate decline" test scenario, update acceptance criteria. Closes: #10 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
git-harden.sh
Audit and harden your global git configuration with security-focused defaults.
Protects against history rewriting, supply chain attacks, credential theft, and malicious repository exploitation. Runs on macOS and Linux.
Quick Start
# Download and run
curl -O https://raw.githubusercontent.com/<you>/git-hardening/main/git-harden.sh
chmod +x git-harden.sh
# Audit your current config (no changes)
./git-harden.sh --audit
# Interactive mode — review and approve each change
./git-harden.sh
# Apply all recommended defaults without prompting
./git-harden.sh -y
What It Does
The script runs in two phases:
- Audit — scans your current
git config --globaland~/.ssh/config, prints a color-coded report:[OK]already set to the recommended value[WARN]set to a non-recommended value[MISS]not configured
- Apply — for each non-OK setting, shows what it does and prompts you to accept or skip (or auto-applies with
-y)
Settings Applied
| Category | What it does |
|---|---|
| Object integrity | Validates all objects on fetch/push/receive (transfer.fsckObjects, etc.) |
| Protocol restrictions | Default-deny policy: only HTTPS and SSH allowed. Blocks git:// (unencrypted) and ext:// (arbitrary command execution) |
| Filesystem protection | Enables core.protectNTFS, core.protectHFS, disables core.fsmonitor |
| Hook control | Redirects core.hooksPath to ~/.config/git/hooks so repo-local hooks can't execute |
| Repository safety | safe.bareRepository=explicit, submodule.recurse=false |
| Pull/merge hardening | pull.ff=only, merge.ff=only — refuses non-fast-forward merges, surfacing rewritten history |
| Transport security | Rewrites http:// to https://, enforces http.sslVerify=true |
| Credential storage | Platform-detected secure helper (osxkeychain on macOS, libsecret on Linux). Warns if using plaintext store |
| Commit signing | SSH-based signing with interactive key setup wizard (software or FIDO2 hardware key) |
| SSH hardening | StrictHostKeyChecking=accept-new, HashKnownHosts=yes, IdentitiesOnly=yes, modern algorithm restrictions |
| Visibility | log.showSignature=true |
A config backup is saved to ~/.config/git/pre-harden-backup-<timestamp>.txt before any changes.
Signing Setup
The script includes an interactive wizard that:
- Detects existing SSH keys (including custom-named keys from
~/.ssh/config) - Detects FIDO2 hardware (YubiKey, etc.)
- Offers two tiers:
- Software SSH key — use existing
ed25519or generate one - FIDO2 hardware key — generate
ed25519-skwith touch-to-sign (if hardware detected)
- Software SSH key — use existing
- Configures
user.signingkey,commit.gpgsign,tag.gpgsign - Sets up
~/.config/git/allowed_signersfor local signature verification
With -y, the script auto-detects the best available key. If no key exists, signing config is prepared but not enabled (to avoid breaking commits).
Usage
git-harden.sh [OPTIONS]
Options:
--audit Audit only, no changes (exit code 2 if issues found)
-y, --yes Auto-apply all recommended defaults
--help, -h Show help
--version Show version
Exit Codes
| Code | Meaning |
|---|---|
| 0 | All OK, or changes applied successfully |
| 1 | Error (missing dependencies, etc.) |
| 2 | Audit found issues (--audit mode) |
Requirements
git>= 2.34.0 (required for SSH signing)ssh-keygen- Bash 3.2+ (compatible with macOS default bash)
Optional:
ykmanorfido2-tokenfor FIDO2 hardware key detection
Threat Model
What this protects against
- History rewriting —
pull.ff=onlyandmerge.ff=onlyrefuse non-fast-forward operations, making force-pushed changes visible - Object injection —
fsckObjectsvalidates every object transferred, catching corruption or malicious payloads - Protocol downgrade — blocks plaintext
git://and dangerousext://protocol - Hook-based RCE — redirects hook execution away from repo-local
.git/hooks/ - Submodule attacks — disables auto-recursion; submodules must be explicitly initialized
- Credential theft — ensures secure credential storage, warns about plaintext
store - Commit impersonation — SSH signing proves key possession (anyone can fake
user.name/user.email) - Filesystem tricks — blocks NTFS/HFS+ path manipulation attacks
What this does NOT protect against
- A compromised machine (malware can use cached keys)
- Malicious code from an authorized signer
- Historical unsigned commits (signing is not retroactive)
- Server-side misconfigurations (see admin recommendations printed by the script)
Admin Recommendations
The script prints (but does not apply) server/org-level recommendations:
- Enable "require signed commits" on protected branches
- Enable GitHub/GitLab vigilant mode
- Restrict force-pushes server-side
- Use fine-grained, short-lived tokens in CI/CD
- Maintain an allowed signers file in repos
- Clone untrusted repos with
--no-recurse-submodules
License
MIT
Description
Languages
Shell
100%