Skip to main content

Common Misconfiguration

Secrets accidentally committed to Git history, stored in Git configuration files, or exposed through Git hooks and submodules.

Vulnerable Example

# VULNERABLE - .git/config with credentials
[core]
    repositoryformatversion = 0
[remote "origin"]
    url = https://username:password123@github.com/org/repo.git
    fetch = +refs/heads/*:refs/remotes/origin/*
[credential]
    helper = store
[http]
    sslKey = /path/to/private/key.pem
    sslCert = /path/to/certificate.pem
    extraHeader = Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

# VULNERABLE - .git-credentials file
https://john.doe:MyPassword123!@github.com
https://oauth2:glpat-xxxxxxxxxxxxxxxxxxxx@gitlab.com
https://x-token-auth:ghp_xxxxxxxxxxxxxxxxxxxx@github.com
# VULNERABLE - Git hooks with hardcoded secrets
#!/bin/bash
# .git/hooks/pre-push

API_KEY="sk_live_4eC39HqLyjWDarjtT1zdp7dc"
WEBHOOK_URL="https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXX"

# Notify deployment system
curl -X POST $WEBHOOK_URL \
  -H "Authorization: Bearer $API_KEY" \
  -d '{"text":"Deployment started"}'

# Push to mirror with hardcoded credentials
git push https://backup:BackupPass123@backup-server.com/repo.git
# VULNERABLE - .gitmodules with credentials
[submodule "private-lib"]
    path = lib/private
    url = https://token:ghp_xxxxxxxxxxxxxxxxxxxx@github.com/org/private-lib.git
[submodule "vendor/secret"]
    path = vendor/secret
    url = https://user:pass@internal-git.company.com/secret-repo.git

Secure Example

# SECURE - Git configuration without credentials
[core]
    repositoryformatversion = 0
[remote "origin"]
    url = git@github.com:org/repo.git  # Use SSH
    fetch = +refs/heads/*:refs/remotes/origin/*
[credential]
    helper = manager-core  # Use credential manager
[url "git@github.com:"]
    insteadOf = https://github.com/  # Force SSH

# SECURE - Using credential helpers
# macOS
git config --global credential.helper osxkeychain

# Windows
git config --global credential.helper manager-core

# Linux
git config --global credential.helper libsecret

# Cache temporarily (for scripts)
git config --global credential.helper 'cache --timeout=3600'
#!/bin/bash
# SECURE - Git hook using environment variables

# Load secrets from secure location
if [ -f "$HOME/.env.secrets" ]; then
    source "$HOME/.env.secrets"
fi

# Or use secret management tool
API_KEY=$(vault kv get -field=api_key secret/deployment)
WEBHOOK_URL=$(vault kv get -field=webhook_url secret/slack)

# Check if secrets are available
if [ -z "$API_KEY" ] || [ -z "$WEBHOOK_URL" ]; then
    echo "Error: Required secrets not found"
    exit 1
fi

# Use the secrets
curl -X POST "$WEBHOOK_URL" \
  -H "Authorization: Bearer $API_KEY" \
  -d '{"text":"Deployment started"}'

# Use SSH agent for authentication
ssh-add -l > /dev/null 2>&1
if [ $? -ne 0 ]; then
    echo "SSH agent not running or no keys loaded"
    exit 1
fi
# SECURE - Python script for Git operations
import subprocess
import os
from pathlib import Path
import git
from git import Repo

class SecureGitManager:
    def __init__(self, repo_path='.'):
        self.repo = Repo(repo_path)
        self.clean_sensitive_data()
        
    def clean_sensitive_data(self):
        """Remove sensitive data from Git history"""
        # Check for common secret patterns
        patterns = [
            r'password\s*=\s*["\'][^"\']+["\']',
            r'api[_-]?key\s*=\s*["\'][^"\']+["\']',
            r'token\s*=\s*["\'][^"\']+["\']',
        ]
        
        # Use git-filter-repo or BFG for cleaning
        # This is a safer alternative to filter-branch
        
    def setup_git_secrets(self):
        """Install and configure git-secrets"""
        commands = [
            # Install git-secrets hooks
            'git secrets --install',
            
            # Register AWS patterns
            'git secrets --register-aws',
            
            # Add custom patterns
            'git secrets --add "sk_live_[0-9a-zA-Z]{24,}"',  # Stripe
            'git secrets --add "ghp_[a-zA-Z0-9]{36}"',       # GitHub
            'git secrets --add "glpat-[a-zA-Z0-9-_]{20}"',   # GitLab
            
            # Add allowed patterns (for false positives)
            'git secrets --add --allowed "example_api_key"',
            
            # Scan repository
            'git secrets --scan',
        ]
        
        for cmd in commands:
            subprocess.run(cmd, shell=True, check=True)
    
    def setup_pre_commit_hooks(self):
        """Setup pre-commit hooks for secret scanning"""
        pre_commit_config = """
repos:
  - repo: https://github.com/Yelp/detect-secrets
    rev: v1.4.0
    hooks:
      - id: detect-secrets
        args: ['--baseline', '.secrets.baseline']
        
  - repo: https://github.com/zricethezav/gitleaks
    rev: v8.18.0
    hooks:
      - id: gitleaks

  - repo: https://github.com/trufflesecurity/trufflehog
    rev: v3.63.0
    hooks:
      - id: trufflehog
        entry: trufflehog filesystem .
        pass_filenames: false
"""
        
        with open('.pre-commit-config.yaml', 'w') as f:
            f.write(pre_commit_config)
        
        # Install pre-commit
        subprocess.run('pre-commit install', shell=True, check=True)
    
    def secure_clone(self, url, path, use_ssh=True):
        """Clone repository securely"""
        if use_ssh:
            # Convert HTTPS to SSH
            if url.startswith('https://github.com/'):
                url = url.replace('https://github.com/', 'git@github.com:')
            elif url.startswith('https://gitlab.com/'):
                url = url.replace('https://gitlab.com/', 'git@gitlab.com:')
        
        # Use deploy keys or SSH agent
        env = os.environ.copy()
        env['GIT_SSH_COMMAND'] = 'ssh -o StrictHostKeyChecking=accept-new'
        
        Repo.clone_from(url, path, env=env)
    
    def add_gitignore_patterns(self):
        """Add security patterns to .gitignore"""
        patterns = [
            # Environment files
            '.env',
            '.env.*',
            '!.env.example',
            
            # Credential files
            '*.pem',
            '*.key',
            '*.p12',
            '*.pfx',
            'credentials.json',
            'service-account-*.json',
            
            # Config with potential secrets
            'config/secrets.yml',
            'config/database.yml',
            'config/application.yml',
            
            # IDE and tool configs
            '.idea/',
            '.vscode/settings.json',
            
            # Terraform
            '*.tfvars',
            '!*.tfvars.example',
            'terraform.tfstate*',
            
            # Kubernetes
            'kubeconfig',
            '*-secret.yaml',
            '*-secrets.yaml',
        ]
        
        gitignore_path = Path('.gitignore')
        existing = gitignore_path.read_text() if gitignore_path.exists() else ''
        
        for pattern in patterns:
            if pattern not in existing:
                existing += f'\n{pattern}'
        
        gitignore_path.write_text(existing.strip() + '\n')

# Git configuration for security
"""
# Global Git configuration for security
git config --global core.hooksPath ~/.git-hooks
git config --global init.templateDir ~/.git-templates
git config --global transfer.fsckObjects true
git config --global receive.fsckObjects true
git config --global fetch.fsckObjects true
"""

Detection Patterns

  • Git credentials URL: https?://[^:]+:[^@]+@.
  • Git config headers: extraHeader\s*=.*Authorization.
  • Credential helpers: helper\s*=\s*store.
  • Submodule URLs with credentials: url\s*=\s*https?://[^:]+:[^@]+@.

Prevention Best Practices

  1. Use SSH keys instead of HTTPS with passwords.
  2. Implement git-secrets or similar tools.
  3. Use credential managers, not credential store.
  4. Scan Git history for secrets before pushing.
  5. Setup pre-commit hooks for secret detection.
  6. Use .gitignore properly.
  7. Implement branch protection rules.
  8. Regular audit of Git configuration.
  9. Use signed commits.
  10. Clean Git history when secrets are found.