Exposure of Version-Control Repository to an Unauthorized Control Sphere
Description
Exposure of Version-Control Repository to an Unauthorized Control Sphere is a vulnerability where a product stores a CVS, Git, SVN, or other version control repository in a directory, archive, or other resource that is accessible to unauthorized actors. Version control repositories contain metadata and details within subdirectories (like .git, .svn, .hg) that could be exploited if exposed on web servers or in distributed archives. This exposure can reveal usernames, commit messages, filenames, path structures, IP addresses, and detailed diff data exposing source code snippets never intended for public access.
Risk
Exposed version control repositories provide attackers with comprehensive reconnaissance information. The complete source code history can be reconstructed from .git directories, revealing security vulnerabilities, hardcoded credentials, API keys, and sensitive business logic. Commit messages may contain security-relevant information like "fixed SQL injection" pointing attackers to vulnerabilities. Author information can be used for social engineering. Internal file paths reveal server structure. Previous versions may contain secrets that were "deleted" but remain in history. Attackers commonly scan for .git/HEAD, .svn/entries, or similar files as part of reconnaissance.
Solution
Remove all version control directories and metadata from production deployments and public-facing servers. Configure web servers to deny access to hidden directories starting with a dot. Use deployment tools that exclude VCS metadata. Implement pre-deployment checks to detect VCS artifacts. Configure .gitignore and similar files to prevent sensitive files from being tracked. Use git archive or equivalent commands that export source without VCS metadata. Block requests to VCS paths at the web server or CDN level. Regularly audit public-facing systems for exposed repositories.
Common Consequences
| Impact | Details |
|---|---|
| Confidentiality | Scope: Confidentiality Read Application Data - Attackers can access source code, configuration files, and sensitive data from the version control history. |
| Confidentiality | Scope: Confidentiality Read Files or Directories - Version control metadata exposes filenames, directory structure, usernames, and other sensitive information about the application and its developers. |
Example Code
Vulnerable Configuration
# Vulnerable: Apache configuration allowing access to VCS directories
<VirtualHost *:80>
ServerName example.com
DocumentRoot /var/www/html
# No restrictions on hidden directories
# .git, .svn, .hg are all accessible
# Attacker can access:
# http://example.com/.git/HEAD
# http://example.com/.git/config
# http://example.com/.git/objects/
# http://example.com/.svn/entries
</VirtualHost>
# Vulnerable: Nginx without VCS directory protection
server {
listen 80;
server_name example.com;
root /var/www/html;
# No location blocks blocking hidden directories
# .git directory fully exposed
}
# Vulnerable: Deployment that includes VCS metadata
#!/bin/bash
# Vulnerable: Copying entire project including .git
cp -r /home/developer/project/* /var/www/html/
# Vulnerable: rsync without exclusions
rsync -avz /home/developer/project/ /var/www/html/
# Vulnerable: tar without exclusions
tar czf release.tar.gz /home/developer/project/
scp release.tar.gz server:/var/www/
# On server, extracted with .git intact
tar xzf release.tar.gz
# Vulnerable: Docker image with VCS directory
FROM nginx:alpine
# Vulnerable: Copies entire directory including .git
COPY . /usr/share/nginx/html/
# .git directory is now in the image and served by nginx
# Vulnerable: CI/CD pipeline without cleanup
# GitHub Actions example
name: Deploy
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
# Vulnerable: Deploys checkout including .git
- name: Deploy to server
run: |
rsync -avz ./ user@server:/var/www/html/
Attacker Reconnaissance
# Attacker discovers exposed .git directory
curl -I https://target.com/.git/HEAD
# HTTP/1.1 200 OK
# Download Git objects
wget -r --no-parent https://target.com/.git/
# Reconstruct repository
cd target.com
git checkout -- .
# View commit history with secrets
git log --all --full-history
git log -p # Show diffs
# Search for secrets in history
git log -p | grep -i "password\|secret\|key\|token"
# Find deleted sensitive files
git log --all --full-history -- "**/config.php"
git show <commit>:config.php
# Automated .git exposure scanner
import requests
def check_git_exposure(url):
endpoints = [
'/.git/HEAD',
'/.git/config',
'/.git/index',
'/.git/logs/HEAD',
'/.svn/entries',
'/.svn/wc.db',
'/.hg/requires',
'/CVS/Root',
]
for endpoint in endpoints:
try:
resp = requests.get(url + endpoint, timeout=5)
if resp.status_code == 200:
print(f"[VULNERABLE] {url}{endpoint}")
return True
except:
pass
return False
Fixed Configuration
# Fixed: Apache blocking VCS directories
<VirtualHost *:80>
ServerName example.com
DocumentRoot /var/www/html
# Fixed: Block all hidden directories
<DirectoryMatch "^\.|\/\.">
Require all denied
</DirectoryMatch>
# Fixed: Explicitly block VCS directories
<DirectoryMatch "(\.git|\.svn|\.hg|CVS)">
Require all denied
</DirectoryMatch>
# Fixed: Block VCS files
<FilesMatch "(\.gitignore|\.gitmodules|\.svn|\.hg)$">
Require all denied
</FilesMatch>
</VirtualHost>
# Fixed: Nginx blocking VCS directories
server {
listen 80;
server_name example.com;
root /var/www/html;
# Fixed: Block all hidden files and directories
location ~ /\. {
deny all;
return 404;
}
# Fixed: Explicitly block VCS directories
location ~ /\.(git|svn|hg|bzr|cvs)/ {
deny all;
return 404;
}
# Fixed: Block specific VCS files
location ~ /\.(gitignore|gitmodules|gitattributes)$ {
deny all;
return 404;
}
}
# Fixed: Deployment scripts excluding VCS metadata
#!/bin/bash
# Fixed: Use git archive to export without .git
git archive --format=tar HEAD | tar -x -C /var/www/html/
# Fixed: rsync with exclusions
rsync -avz \
--exclude='.git' \
--exclude='.svn' \
--exclude='.hg' \
--exclude='.gitignore' \
--exclude='CVS' \
/home/developer/project/ /var/www/html/
# Fixed: tar with exclusions
tar czf release.tar.gz \
--exclude='.git' \
--exclude='.svn' \
--exclude='.hg' \
/home/developer/project/
# Fixed: Find and remove any VCS directories after deployment
find /var/www/html -type d -name ".git" -exec rm -rf {} + 2>/dev/null
find /var/www/html -type d -name ".svn" -exec rm -rf {} + 2>/dev/null
find /var/www/html -type d -name ".hg" -exec rm -rf {} + 2>/dev/null
# Fixed: Verification
if [ -d "/var/www/html/.git" ]; then
echo "ERROR: .git directory found in deployment!"
exit 1
fi
# Fixed: Docker image without VCS directories
FROM nginx:alpine
# Fixed: Use .dockerignore to exclude VCS
# .dockerignore contents:
# .git
# .svn
# .hg
# .gitignore
# .gitmodules
# Or explicitly copy only needed files
COPY --chown=nginx:nginx src/ /usr/share/nginx/html/
COPY --chown=nginx:nginx public/ /usr/share/nginx/html/
# Fixed: Remove any VCS artifacts that might slip through
RUN find /usr/share/nginx/html -name ".git*" -type d -exec rm -rf {} + 2>/dev/null || true && \
find /usr/share/nginx/html -name ".svn" -type d -exec rm -rf {} + 2>/dev/null || true
# Fixed: CI/CD pipeline with proper cleanup
name: Deploy
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
# Fixed: Remove VCS artifacts before deployment
- name: Clean VCS artifacts
run: |
rm -rf .git .gitignore .gitmodules
find . -name ".git*" -type d -exec rm -rf {} + 2>/dev/null || true
# Fixed: Or use git archive
- name: Create clean archive
run: |
git archive --format=tar --output=release.tar HEAD
mkdir deploy
tar -xf release.tar -C deploy/
- name: Deploy to server
run: |
rsync -avz --delete deploy/ user@server:/var/www/html/
# Fixed: Verify deployment
- name: Verify no VCS exposed
run: |
if curl -s -o /dev/null -w "%{http_code}" https://example.com/.git/HEAD | grep -q "200"; then
echo "ERROR: .git directory is exposed!"
exit 1
fi
# Fixed: Pre-deployment check script
import os
import sys
def check_vcs_artifacts(deploy_dir):
"""Check for VCS artifacts before deployment."""
vcs_patterns = ['.git', '.svn', '.hg', 'CVS', '.bzr']
found = []
for root, dirs, files in os.walk(deploy_dir):
for pattern in vcs_patterns:
if pattern in dirs:
found.append(os.path.join(root, pattern))
for f in files:
if f.startswith('.git'):
found.append(os.path.join(root, f))
if found:
print("ERROR: VCS artifacts found in deployment directory:")
for path in found:
print(f" - {path}")
return False
return True
if __name__ == '__main__':
deploy_dir = sys.argv[1] if len(sys.argv) > 1 else '/var/www/html'
if not check_vcs_artifacts(deploy_dir):
sys.exit(1)
print("OK: No VCS artifacts found")
CVE Examples
No specific CVEs are listed in the MITRE database for this CWE. However, exposed Git repositories have been involved in numerous security incidents:
- Exposed
.gitdirectories have led to source code leaks at major companies - Credentials found in Git history have enabled account takeovers
- This is a common finding in bug bounty programs
References
- MITRE Corporation. "CWE-527: Exposure of Version-Control Repository to an Unauthorized Control Sphere." https://cwe.mitre.org/data/definitions/527.html
- OWASP. "Source Code Disclosure."
- GitTools. "Tools for exploiting exposed .git directories."