Git
To dump a .git folder from a URL use https://github.com/arthaud/git-dumper
Use https://www.gitkraken.com/ to inspect the content
If a .git directory is found in a web application you can download all the content using wget -r http://web.com/.git. Then, you can see the changes made by using git diff.
The tools: Git-Money, DVCS-Pillage and GitTools can be used to retrieve the content of a git directory.
The tool https://github.com/cve-search/git-vuln-finder can be used to search for CVEs and security vulnerability messages inside commits messages.
The tool Gitrob searches for sensitive data in an organization’s repositories and in repositories associated with its employees.
Repo security scanner is a command line-based tool that was written with a single goal: to help you discover GitHub secrets that developers accidentally made by pushing sensitive data. And like the others, it will help you find passwords, private keys, usernames, tokens and more.
Here you can find a study of GitHub dorks: https://securitytrails.com/blog/github-dorks
Faster /.git dumping & dirlisting bypass (2024–2026)
- holly-hacker/git-dumper is a 2024 rewrite of the classic GitTools dumper with parallel fetching (>10x speedup). Example:
python3 git-dumper.py https://victim/.git/ out && cd out && git checkout -- .[1] - Ebryx/GitDump brute-forces object names from
.git/index,packed-refs, etc. to recover repos even when directory traversal is disabled:python3 git-dump.py https://victim/.git/ dump && cd dump && git checkout -- .[2]
Quick post-dump triage
cd dumpdir
# reconstruct working tree
git checkout -- .
# show branch/commit map
git log --graph --oneline --decorate --all
# list suspicious config/remotes/hooks
git config -l
ls .git/hooks
Secret/credential hunting (current tooling)
- TruffleHog v3+: detector-based scanning with automatic Git history traversal. Detectors can combine pattern matching, decoding or entropy checks, and live credential verification;
--only-verifiedkeeps only results that a detector could verify.trufflehog git file://$PWD --only-verified --json > secrets.json[7] - Gitleaks: fast ruleset-based scanning of a working tree or Git history. Current releases use
gitleaks git . --report-format json --report-path gitleaks.json; older v8 releases usedgitleaks detect -v --source . --report-format json --report-path gitleaks.json, which remains useful when reproducing an older environment.[8]
Server-side Git integrations as an attack surface
If the application clones attacker-controlled repositories and later runs git operations from a web/API action (status, diff, checkout, pull, merge, commit, dependency sync, package install, branch switch…), treat Git itself as part of the server-side attack surface.[3]
Git config / hook abuse when the backend uses the native Git CLI
If you can write or append to .git/config, several directives can turn a low-impact file write into server-side command execution during later Git actions:[3]
| Directive | Common trigger | Abuse |
|---|---|---|
core.fsmonitor | git status, git diff | Executes an external helper on common working-tree operations |
core.sshCommand / core.gitProxy | git fetch, git push, git clone | Replaces the transport command |
credential.helper | Authenticated Git operations | Runs a shell helper for credential lookup/storage |
filter.<name>.clean / filter.<name>.smudge | git add, git checkout, git clone | Executes external clean/smudge filters |
diff.external | git diff | Executes an external diff tool |
core.hooksPath | commit / checkout / merge / push | Redirects hook execution to an attacker-controlled directory |
- Append-only writes can still work: Git accepts duplicate INI sections and the last value may win, so appending a second
[core]section can be enough. - Direct hook write also works if you can plant files inside
.git/hooks/such aspost-checkout,post-merge, orpre-commit. - This is mainly a native Git CLI primitive. JGit/libgit2/go-git usually do not execute the same hooks/config helpers, although they can still be exploitable through path and symlink handling.
hooksPath overwrite via path traversal
Modern web apps sometimes regenerate .git/config from user-controlled repo names, dependency names, refs, or workspace identifiers. If one value lands inside core.hooksPath and another one controls where the generated config is written, you can chain both into RCE:[3][6]
- Path traversal in
hooksPath: if a repo/dependency name is copied intohooksPath, inject../../..to escape the intended hooks directory and point to a writable location. This is effectively a path traversal in Git config. - Overwrite another repo’s
.git/config: ifref/ branch / destination path controls where generated Git metadata is written, traverse into another workspace and replace its config. - Force intermediate directories to exist: abuse clone destination controls so the backend creates paths such as
../../git_hooksfor you. - Ship executable hooks: set the executable bit inside Git metadata so every clone writes the hook with mode
100755:git update-index --chmod=+x pre-commit - Find a native Git code path: libraries like JGit ignore hooks. Hunt for features that fall back to system Git so hooks will actually run.
- Race the config rewrite: if the app restores
.git/configright before invoking Git, keep overwriting it while triggering the Git action to win a race condition.
Buried bare repositories & repo-detection abuse
Git discovers repositories by walking upward and looking for HEAD, config, objects/, and refs/. Therefore, an attacker can bury a bare repository inside a normal repository subdirectory and wait until the service runs Git from there.[3][5]
- Create a nested bare repo.
- Change
bare = truetobare = false. - Add
core.worktreeand an execution directive such ascore.fsmonitor. - If the service later
cds into that folder and runsgit status/git diff, Git loads the buried config and executes your helper.
Also check whether deleting/corrupting .git/HEAD could make Git stop recognizing the intended repository and fall through to a planted bare repo in the same or parent directory.
Git argument injection and unsafe shell construction
When untrusted filenames, branch names, refs, or paths are passed to Git without --, values starting with - / -- may be parsed as options instead of positional arguments.[4]
# Vulnerable
git checkout $branch
git rm $path
# Safer
git checkout -- "$branch"
git rm -- "$path"
Interesting primitives to test:[3]
--pathspec-from-file=<file>withgit rmto make Git read pathspecs from an arbitrary file and leak content via errors.- Any workflow that joins argv into a shell string instead of using a real argument array.
- Cases where the backend safely escapes Git arguments but still embeds an unescaped working directory in a shell command like
cd #{working_directory} && git ...; if you can control the directory name, shell syntax such as$(id)may execute before Git starts.
Symlink-based repository escape
Git stores symlinks as blob targets. If checkout materializes real symlinks and the web UI/API follows symlinks, a repository-scoped file read/write primitive can become filesystem escape:[3]
repo/
link -> ../../../etc/
Then repo/link/passwd may resolve to /etc/passwd, and writes through that path may escape the repository boundary too.[3]
Extra pivot points:[3]
- Blacklist bypass via repo-internal symlinks: if the app blocks direct
.git/reads with a prefix check, look for alternative paths such asnode_modules/pkg/.git/configthat resolve back to the real repo root through symlinks. - JGit
core.symlinksabuse: even if JGit ignores classic config-to-RCE directives, writingsymlinks = truein.git/configcan make the next pull/checkout materialize attacker-controlled symlinks, exposing broader filesystem paths or even other tenants’ repositories if storage is shared.
Quick checklist when you find a Git-backed file primitive
- File read: inspect
.git/configfor credentials, remote URLs, internal paths, repo layout, and deployment metadata. - File write / append: target
.git/config,.git/hooks/*, or alternate repo markers (HEAD,config,objects/,refs/) to escalate into command execution or repo confusion. - File delete: test whether removing
.git/HEADchanges which repository Git discovers. - Path traversal / arbitrary folder creation: look for generated clone destinations, dependency sync paths, worktrees, hook paths, and package install directories.
- Package installation features: local npm dependencies (
"pkg": "./",file:) may create symlinks undernode_modules/that help bypass path blacklists and reach.git/configindirectly.
References
- [1] holly-hacker/git-dumper – parallel fast /.git dumper
- [2] Ebryx/GitDump
- [3] The gift that keeps giving: Exploiting Git Integrations in Cloud Services
- [4] Argument Injection Vectors (SonarSource)
- [5] Git buried bare repos and fsmonitor abuses (justinsteven)
- [6] LookOut: RCE and internal access on Looker (Tenable)
- [7] TruffleHog documentation
- [8] Gitleaks documentation