Common Misconfiguration
Secrets accidentally committed to Git history, stored in Git configuration files, or exposed through Git hooks and submodules.Vulnerable Example
Copy
# 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
Copy
# 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
Copy
# 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
Copy
# 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'
Copy
#!/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
Copy
# 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
- Use SSH keys instead of HTTPS with passwords.
- Implement git-secrets or similar tools.
- Use credential managers, not credential store.
- Scan Git history for secrets before pushing.
- Setup pre-commit hooks for secret detection.
- Use .gitignore properly.
- Implement branch protection rules.
- Regular audit of Git configuration.
- Use signed commits.
- Clean Git history when secrets are found.

