From da2ffea1329823aecc4d0f6da400dfdbc66d6e95 Mon Sep 17 00:00:00 2001 From: Flo Date: Mon, 30 Mar 2026 14:00:04 +0200 Subject: [PATCH] docs: add README with usage, settings, and threat model Co-Authored-By: Claude --- README.md | 128 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..e4d27de --- /dev/null +++ b/README.md @@ -0,0 +1,128 @@ +# 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 + +```bash +# Download and run +curl -O https://raw.githubusercontent.com//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: + +1. **Audit** — scans your current `git config --global` and `~/.ssh/config`, prints a color-coded report: + - `[OK]` already set to the recommended value + - `[WARN]` set to a non-recommended value + - `[MISS]` not configured +2. **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-.txt` before any changes. + +### Signing Setup + +The script includes an interactive wizard that: + +1. Detects existing SSH keys (including custom-named keys from `~/.ssh/config`) +2. Detects FIDO2 hardware (YubiKey, etc.) +3. Offers two tiers: + - **Software SSH key** — use existing `ed25519` or generate one + - **FIDO2 hardware key** — generate `ed25519-sk` with touch-to-sign (if hardware detected) +4. Configures `user.signingkey`, `commit.gpgsign`, `tag.gpgsign` +5. Sets up `~/.config/git/allowed_signers` for 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: +- `ykman` or `fido2-token` for FIDO2 hardware key detection + +## Threat Model + +### What this protects against + +- **History rewriting** — `pull.ff=only` and `merge.ff=only` refuse non-fast-forward operations, making force-pushed changes visible +- **Object injection** — `fsckObjects` validates every object transferred, catching corruption or malicious payloads +- **Protocol downgrade** — blocks plaintext `git://` and dangerous `ext://` 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