Files
gh-josiahsiegel-claude-code…/skills/git-security-2025.md
2025-11-30 08:29:08 +08:00

16 KiB

name, description
name description
git-security-2025 Git security best practices for 2025 including signed commits, zero-trust workflows, secret scanning, and verification

🚨 CRITICAL GUIDELINES

Windows File Path Requirements

MANDATORY: Always Use Backslashes on Windows for File Paths

When using Edit or Write tools on Windows, you MUST use backslashes (\) in file paths, NOT forward slashes (/).

Examples:

  • WRONG: D:/repos/project/file.tsx
  • CORRECT: D:\repos\project\file.tsx

This applies to:

  • Edit tool file_path parameter
  • Write tool file_path parameter
  • All file operations on Windows systems

Documentation Guidelines

NEVER create new documentation files unless explicitly requested by the user.

  • Priority: Update existing README.md files rather than creating new documentation
  • Repository cleanliness: Keep repository root clean - only README.md unless user requests otherwise
  • Style: Documentation should be concise, direct, and professional - avoid AI-generated tone
  • User preference: Only create additional .md files when user specifically asks for documentation

Git Security Best Practices 2025

Zero-Trust Security Model (2025 Standard)

What: Every developer identity must be authenticated and authorized explicitly. All Git operations are logged, signed, and continuously monitored.

Core Principles:

  1. Never trust, always verify - Every commit verified
  2. Least privilege access - Minimal permissions required
  3. Continuous monitoring - All operations logged and audited
  4. Assume breach - Defense in depth strategies

Implementing Zero-Trust for Git

1. Mandatory Signed Commits:

# Global requirement
git config --global commit.gpgsign true
git config --global tag.gpgsign true

# Enforce via branch protection (GitHub/GitLab/Azure DevOps)
# Repository Settings → Branches → Require signed commits

2. Identity Verification:

# Every commit must verify identity
git log --show-signature -10

# Reject unsigned commits in CI/CD
# .github/workflows/verify.yml
- name: Verify all commits are signed
  run: |
    git log --pretty="%H" origin/main..HEAD | while read commit; do
      if ! git verify-commit "$commit" 2>/dev/null; then
        echo "ERROR: Unsigned commit $commit"
        exit 1
      fi
    done

3. Continuous Audit Logging:

# Enable Git audit trail
git config --global alias.audit 'log --all --pretty="%H|%an|%ae|%ad|%s|%GK" --date=iso'

# Export audit log
git audit > git-audit.log

# Monitor for suspicious activity
git log --author="*" --since="24 hours ago" --pretty=format:"%an %ae %s"

4. Least Privilege Access:

# GitHub branch protection (zero-trust model)
branches:
  main:
    protection_rules:
      required_pull_request_reviews: true
      dismiss_stale_reviews: true
      require_code_owner_reviews: true
      required_approving_review_count: 2
      require_signed_commits: true
      enforce_admins: true
      restrictions:
        users: []  # No direct push
        teams: ["security-team"]

5. Continuous Monitoring:

# Monitor all repository changes
# .github/workflows/security-monitor.yml
name: Security Monitoring
on: [push, pull_request]
jobs:
  monitor:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Check for unsigned commits
        run: git verify-commit HEAD || echo "::warning::Unsigned commit detected"

      - name: Scan for secrets
        run: gitleaks detect --exit-code 1

      - name: Check commit author
        run: |
          AUTHOR=$(git log -1 --format='%an <%ae>')
          echo "Commit by: $AUTHOR"
          # Log to SIEM/security monitoring

Signed Commits (Mandatory in 2025)

Why: Cryptographically verify commit authorship, prevent impersonation, ensure audit trail.

Industry Trend: Signed commits increasingly required in 2025 workflows.

GPG Signing (Traditional)

Setup:

# Generate GPG key
gpg --full-generate-key
# Choose: RSA and RSA, 4096 bits, expires in 2y

# List keys
gpg --list-secret-keys --keyid-format=long

# Example output:
# sec   rsa4096/ABC123DEF456 2025-01-15 [SC] [expires: 2027-01-15]
# uid                 [ultimate] Your Name <your.email@example.com>
# ssb   rsa4096/GHI789JKL012 2025-01-15 [E] [expires: 2027-01-15]

# Configure Git
git config --global user.signingkey ABC123DEF456
git config --global commit.gpgsign true
git config --global tag.gpgsign true

# Export public key for GitHub/GitLab
gpg --armor --export ABC123DEF456
# Copy output and add to GitHub/GitLab/Bitbucket

# Sign commits
git commit -S -m "feat: add authentication"

# Verify signatures
git log --show-signature
git verify-commit HEAD
git verify-tag v1.0.0

Troubleshooting:

# GPG agent not running
export GPG_TTY=$(tty)
echo 'export GPG_TTY=$(tty)' >> ~/.bashrc

# Cache passphrase longer
echo 'default-cache-ttl 34560000' >> ~/.gnupg/gpg-agent.conf
echo 'max-cache-ttl 34560000' >> ~/.gnupg/gpg-agent.conf
gpg-connect-agent reloadagent /bye

# Test signing
echo "test" | gpg --clearsign

SSH Signing (Modern Alternative - 2023+)

Why SSH: Simpler, reuse existing SSH keys, no GPG required.

Setup:

# Check if SSH key exists
ls -la ~/.ssh/id_ed25519.pub

# Generate if needed
ssh-keygen -t ed25519 -C "your.email@example.com"

# Configure Git to use SSH signing
git config --global gpg.format ssh
git config --global user.signingkey ~/.ssh/id_ed25519.pub
git config --global commit.gpgsign true

# Add public key to GitHub
cat ~/.ssh/id_ed25519.pub
# GitHub Settings → SSH and GPG keys → New SSH key → Key type: Signing Key

# Sign commits (automatic with commit.gpgsign=true)
git commit -m "feat: add feature"

# Verify
git log --show-signature

Configure allowed signers file (for verification):

# Create allowed signers file
echo "your.email@example.com $(cat ~/.ssh/id_ed25519.pub)" > ~/.ssh/allowed_signers

# Configure Git
git config --global gpg.ssh.allowedSignersFile ~/.ssh/allowed_signers

# Verify commits
git verify-commit HEAD

Secret Scanning & Prevention

GitHub Secret Scanning (Push Protection)

Enable in repository:

  • Settings → Code security → Secret scanning → Enable
  • Enable push protection (blocks secrets at push time)

AI-powered detection (2025):

  • AWS credentials
  • Azure service principals
  • Google Cloud keys
  • GitHub tokens
  • Database connection strings
  • API keys (OpenAI, Stripe, Anthropic, etc.)
  • Private keys
  • OAuth tokens
  • Custom patterns

Example blocked push:

$ git push
remote: error: GH013: Repository rule violations found for refs/heads/main.
remote:
remote: - Push cannot contain secrets
remote:
remote:   Resolve the following violations before pushing again
remote:
remote:   — AWS Access Key
remote:     locations:
remote:       - config.py:12
remote:
remote:   (Disable push protection: https://github.com/settings/security_analysis)
remote:
To github.com:user/repo.git
 ! [remote rejected] main -> main (push declined due to repository rule violations)

Fix:

# Remove secret from file
# Use environment variable instead
echo "AWS_ACCESS_KEY=your_key" >> .env
echo ".env" >> .gitignore

# Remove from history if already committed
git rm --cached config.py
git commit -m "Remove secrets"

# If in history, use filter-repo
git filter-repo --path config.py --invert-paths
git push --force

Gitleaks (Local Scanning)

Install:

# macOS
brew install gitleaks

# Linux
wget https://github.com/gitleaks/gitleaks/releases/download/v8.18.0/gitleaks_8.18.0_linux_x64.tar.gz
tar -xzf gitleaks_8.18.0_linux_x64.tar.gz
sudo mv gitleaks /usr/local/bin/

# Windows
choco install gitleaks

Usage:

# Scan entire repository
gitleaks detect

# Scan uncommitted changes
gitleaks protect

# Scan specific directory
gitleaks detect --source ./src

# Generate report
gitleaks detect --report-format json --report-path gitleaks-report.json

# Use in CI/CD
gitleaks detect --exit-code 1

Pre-commit hook:

# .git/hooks/pre-commit
#!/bin/bash
gitleaks protect --staged --verbose
if [ $? -ne 0 ]; then
    echo "⚠️  Gitleaks detected secrets. Commit blocked."
    exit 1
fi

Git-secrets (AWS-focused)

# Install
brew install git-secrets  # macOS
# or
git clone https://github.com/awslabs/git-secrets.git
cd git-secrets
sudo make install

# Initialize in repository
git secrets --install
git secrets --register-aws

# Add custom patterns
git secrets --add 'password\s*=\s*[^\s]+'
git secrets --add 'api[_-]?key\s*=\s*[^\s]+'

# Scan
git secrets --scan
git secrets --scan-history

Enforce Signed Commits

Branch Protection Rules

GitHub:

Repository → Settings → Branches → Branch protection rules
☑ Require signed commits
☑ Require linear history
☑ Require status checks to pass

GitLab:

Repository → Settings → Repository → Protected branches
☑ Allowed to push: No one
☑ Allowed to merge: Maintainers
☑ Require all commits be signed

Azure DevOps:

Branch Policies → Add policy → Require signed commits

Pre-receive Hook (Server-side enforcement)

#!/bin/bash
# .git/hooks/pre-receive (on server)

zero_commit="0000000000000000000000000000000000000000"

while read oldrev newrev refname; do
  # Skip branch deletion
  if [ "$newrev" = "$zero_commit" ]; then
    continue
  fi

  # Check all commits in push
  for commit in $(git rev-list "$oldrev".."$newrev"); do
    # Verify commit signature
    if ! git verify-commit "$commit" 2>/dev/null; then
      echo "Error: Commit $commit is not signed"
      echo "All commits must be signed. Configure with:"
      echo "  git config commit.gpgsign true"
      exit 1
    fi
  done
done

exit 0

Security Configuration

# Enforce signed commits
git config --global commit.gpgsign true
git config --global tag.gpgsign true

# Use SSH signing (modern)
git config --global gpg.format ssh
git config --global user.signingkey ~/.ssh/id_ed25519.pub

# Security settings
git config --global protocol.version 2
git config --global transfer.fsckobjects true
git config --global fetch.fsckobjects true
git config --global receive.fsckobjects true

# Prevent credential leaks
git config --global credential.helper cache --timeout=3600
# Or use system credential manager
git config --global credential.helper wincred  # Windows
git config --global credential.helper osxkeychain  # macOS

# Line ending safety
git config --global core.autocrlf true  # Windows
git config --global core.autocrlf input  # macOS/Linux

# Editor safety (avoid nano/vim leaks)
git config --global core.editor "code --wait"

.gitignore Security

# Secrets
.env
.env.*
*.pem
*.key
*.p12
*.pfx
*_rsa
*_dsa
*_ecdsa
*_ed25519
credentials.json
secrets.yaml
config/secrets.yml

# Cloud provider
.aws/
.azure/
.gcloud/
gcloud-service-key.json

# Databases
*.sqlite
*.db

# Logs (may contain sensitive data)
*.log
logs/

# IDE secrets
.vscode/settings.json
.idea/workspace.xml

# Build artifacts (may contain embedded secrets)
dist/
build/
node_modules/
vendor/

Credential Management

SSH Keys

# Generate secure SSH key
ssh-keygen -t ed25519 -C "your.email@example.com" -f ~/.ssh/id_ed25519_work

# Use ed25519 (modern, secure, fast)
# Avoid RSA < 4096 bits
# Avoid DSA (deprecated)

# Configure SSH agent
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519_work

# Test connection
ssh -T git@github.com

# Use different keys for different services
# ~/.ssh/config
Host github.com
  IdentityFile ~/.ssh/id_ed25519_github

Host gitlab.com
  IdentityFile ~/.ssh/id_ed25519_gitlab

HTTPS Credentials

# Use credential manager (not plaintext!)

# Windows
git config --global credential.helper wincred

# macOS
git config --global credential.helper osxkeychain

# Linux (libsecret)
git config --global credential.helper /usr/share/git/credential/libsecret/git-credential-libsecret

# Cache for limited time (temporary projects)
git config --global credential.helper 'cache --timeout=3600'

Personal Access Tokens (PAT)

GitHub:

  • Settings → Developer settings → Personal access tokens → Fine-grained tokens
  • Set expiration (max 1 year)
  • Minimum scopes needed
  • Use for HTTPS authentication

Never commit tokens:

# Use environment variable
export GITHUB_TOKEN="ghp_xxxxxxxxxxxx"
git clone https://$GITHUB_TOKEN@github.com/user/repo.git

# Or use Git credential helper
gh auth login  # GitHub CLI method

CodeQL & Security Scanning

GitHub CodeQL

.github/workflows/codeql.yml:

name: "CodeQL Security Scan"

on:
  push:
    branches: [ main, develop ]
  pull_request:
    branches: [ main ]
  schedule:
    - cron: '0 0 * * 1'  # Weekly scan

jobs:
  analyze:
    name: Analyze
    runs-on: ubuntu-latest
    permissions:
      security-events: write
      contents: read

    strategy:
      fail-fast: false
      matrix:
        language: [ 'javascript', 'python', 'java' ]

    steps:
    - name: Checkout repository
      uses: actions/checkout@v4

    - name: Initialize CodeQL
      uses: github/codeql-action/init@v3
      with:
        languages: ${{ matrix.language }}
        queries: security-and-quality

    - name: Autobuild
      uses: github/codeql-action/autobuild@v3

    - name: Perform CodeQL Analysis
      uses: github/codeql-action/analyze@v3
      with:
        category: "/language:${{ matrix.language }}"

Detects:

  • SQL injection
  • XSS vulnerabilities
  • Path traversal
  • Command injection
  • Insecure deserialization
  • Authentication bypass
  • Hardcoded secrets

Audit Trail

Enable detailed logging

# Log all Git operations
git config --global alias.ll 'log --all --graph --decorate --oneline --show-signature'

# Check commit verification
git log --show-signature -10

# Export audit log
git log --pretty=format:"%H,%an,%ae,%ad,%s" --date=iso > git-audit.csv

# Verify all commits in branch
git log --show-signature main..HEAD

Security Checklist

Repository Setup:

  • ☑ Enable branch protection
  • ☑ Require signed commits
  • ☑ Enable secret scanning with push protection
  • ☑ Enable CodeQL or similar scanning
  • ☑ Configure Dependabot/Renovate
  • ☑ Require 2FA for all contributors

Developer Workstation:

  • ☑ Use GPG or SSH commit signing
  • ☑ Configure credential manager (never plaintext)
  • ☑ Install and configure gitleaks
  • ☑ Create comprehensive .gitignore
  • ☑ Enable fsckobjects for transfers
  • ☑ Use SSH keys with passphrase

Workflow:

  • ☑ Never commit secrets
  • ☑ Review changes before commit
  • ☑ Verify signatures on pull/merge
  • ☑ Regular security audits
  • ☑ Rotate credentials periodically
  • ☑ Use environment variables for secrets

Incident Response

Secret leaked in commit:

# 1. Rotate compromised credentials IMMEDIATELY
# 2. Remove from latest commit (if not pushed)
git reset HEAD~1
# Edit files to remove secret
git add .
git commit -m "Remove secrets"

# 3. If pushed, remove from history
git filter-repo --path config/secrets.yml --invert-paths
git push --force

# 4. Notify team to re-clone
# 5. Enable push protection to prevent future leaks

Unsigned commits detected:

# Identify unsigned commits
git log --show-signature | grep "No signature"

# Re-sign commits (if you authored them)
git rebase --exec 'git commit --amend --no-edit -n -S' -i HEAD~10

# Force push (with team coordination)
git push --force-with-lease

Resources