Exposed .git directory: git-dumper and secrets in the history
How to spot an exposed .git folder on a website, rebuild the repository with git-dumper and find passwords and keys in the commit history.
If the developer deployed the site by copying the project folder as it was, the .git directory travelled with it. From outside you can download it and rebuild all the source code and, even better, its whole history: every password someone committed by mistake and then "deleted" is still in an old commit.
It is one of the most rewarding findings on a machine: you go from black box to having the code, and often straight credentials.
Detecting it
curl -s http://target.htb/.git/HEAD
# ref: refs/heads/master ← exposed
Other signs:
nmap -sCreports it on its own: thehttp-gitscript printsGit repository found!.- Directory fuzzing with any common wordlist finds
.git/(more in the web fuzzing guide). - Also try every vhost and subdomain: on LinkVortex it only exists on
dev..
If /.git/ returns 403 but /.git/HEAD or /.git/config return 200, it is exposed anyway: only directory listing is forbidden.
Dumping it with git-dumper
pipx install git-dumper
git-dumper http://target.htb/.git/ ./repo
cd repo && git status && git log --oneline --all
git-dumper follows the references from HEAD, downloads the objects one by one and rebuilds the working tree, even with directory listing disabled.
Note
If it fails, GitTools (gitdumper.sh + extractor.sh) is the classic alternative. The extractor dumps each commit into its own folder, handy when the repository is broken.
Hunting for secrets in the history
First the current code: config files, .env, database connection strings and hidden routes. Then the history:
git log -p --all | grep -iE "pass|secret|token|key|pwd" | head -50 # changes with keywords
git log --all --stat # which files each commit touched
git show <commit> # a whole commit
git log --all --diff-filter=D --name-only # files that were deleted
git stash list; git branch -a; git tag # forgotten branches and stash
To avoid searching by hand, let a secret scanner do it:
trufflehog git file://$(pwd) --no-update
gitleaks detect -s . -v
| What to look for | Why |
|---|---|
| Commits with messages like "remove credentials" or "cleanup" | The one right before has the password (OpenSource, Seal) |
The token signing key (SECRET_KEY, JWT_SECRET) |
Lets you forge admin sessions (Secret; see JWT attacks) |
.git/config |
Sometimes the remote URL carries a username and password: https://user:pass@gitea... |
Hooks and CI (.git/hooks, .gitlab-ci.yml) |
They reveal how it is deployed and what runs after a push (Bitlab) |
Reading the code to find the bug
With the code, you stop searching blind. Look for the language's dangerous functions and trace where their input comes from:
grep -rnE "system\(|exec\(|eval\(|popen|shell_exec|unserialize|pickle.loads|render_template_string" .
grep -rnE "SELECT .*\+|query\(.*\\\$" . # queries built by concatenation
That leads to the guide for each bug: command injection, SSTI, deserialization or SQL injection.
The same trick elsewhere
- SVN:
/.svn/wc.dbis a SQLite database with the files;svnorsvn-extractorrebuild it. There are credentials in an old revision on Worker. - Mercurial and Bazaar:
/.hg/and/.bzr/, with equivalent tools. - Docker images: each layer is like a commit.
docker save+ unpacking the layers shows files that were deleted later (Bolt). - Gitea or GitLab servers inside the network: browse public repositories and the history of each one.