git.md (11499B)
1 --- 2 title: "Git" 3 section: "Network Services" 4 sectionSlug: "network-services-pentesting" 5 sourcePath: "src/network-services-pentesting/pentesting-web/git.md" 6 sourceUrl: "https://github.com/HackTricks-wiki/hacktricks/blob/188de82beb54e70956b2952367a0af91d26758b8/src/network-services-pentesting/pentesting-web/git.md" 7 sha: "188de82beb54e70956b2952367a0af91d26758b8" 8 isIndex: false 9 modified: true 10 license: "CC-BY-NC-4.0" 11 --- 12 13 # Git 14 15 **To dump a .git folder from a URL use** [**https://github.com/arthaud/git-dumper**](https://github.com/arthaud/git-dumper) 16 17 **Use** [**https://www.gitkraken.com/**](https://www.gitkraken.com/) **to inspect the content** 18 19 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_. 20 21 The tools: [Git-Money](https://github.com/dnoiz1/git-money), [DVCS-Pillage](https://github.com/evilpacket/DVCS-Pillage) and [GitTools](https://github.com/internetwache/GitTools) can be used to retrieve the content of a git directory. 22 23 The tool [https://github.com/cve-search/git-vuln-finder](https://github.com/cve-search/git-vuln-finder) can be used to search for CVEs and security vulnerability messages inside commits messages. 24 25 The tool [Gitrob](https://github.com/michenriksen/gitrob) searches for sensitive data in an organization's repositories and in repositories associated with its employees. 26 27 [Repo security scanner](https://github.com/UKHomeOffice/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. 28 29 Here you can find a study of GitHub dorks: [https://securitytrails.com/blog/github-dorks](https://securitytrails.com/blog/github-dorks) 30 31 ### Faster /.git dumping & dirlisting bypass (2024–2026) 32 33 * [holly-hacker/git-dumper](https://github.com/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 -- .`<sup>[[1]](#references)</sup> 34 * [Ebryx/GitDump](https://github.com/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 -- .`<sup>[[2]](#references)</sup> 35 36 ### Quick post-dump triage 37 38 ```bash 39 cd dumpdir 40 # reconstruct working tree 41 git checkout -- . 42 # show branch/commit map 43 git log --graph --oneline --decorate --all 44 # list suspicious config/remotes/hooks 45 git config -l 46 ls .git/hooks 47 ``` 48 49 ### Secret/credential hunting (current tooling) 50 51 * **TruffleHog v3+**: detector-based scanning with automatic Git history traversal. Detectors can combine pattern matching, decoding or entropy checks, and live credential verification; `--only-verified` keeps only results that a detector could verify. `trufflehog git file://$PWD --only-verified --json > secrets.json`<sup>[[7]](#references)</sup> 52 * **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 used `gitleaks detect -v --source . --report-format json --report-path gitleaks.json`, which remains useful when reproducing an older environment.<sup>[[8]](#references)</sup> 53 54 ### Server-side Git integrations as an attack surface 55 56 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**.<sup>[[3]](#references)</sup> 57 58 ### Git config / hook abuse when the backend uses the native Git CLI 59 60 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:<sup>[[3]](#references)</sup> 61 62 | Directive | Common trigger | Abuse | 63 | --- | --- | --- | 64 | `core.fsmonitor` | `git status`, `git diff` | Executes an external helper on common working-tree operations | 65 | `core.sshCommand` / `core.gitProxy` | `git fetch`, `git push`, `git clone` | Replaces the transport command | 66 | `credential.helper` | Authenticated Git operations | Runs a shell helper for credential lookup/storage | 67 | `filter.<name>.clean` / `filter.<name>.smudge` | `git add`, `git checkout`, `git clone` | Executes external clean/smudge filters | 68 | `diff.external` | `git diff` | Executes an external diff tool | 69 | `core.hooksPath` | commit / checkout / merge / push | Redirects hook execution to an attacker-controlled directory | 70 71 * **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. 72 * **Direct hook write** also works if you can plant files inside `.git/hooks/` such as `post-checkout`, `post-merge`, or `pre-commit`. 73 * 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. 74 75 ### `hooksPath` overwrite via path traversal 76 77 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:<sup>[[3]](#references)</sup><sup>[[6]](#references)</sup> 78 79 * **Path traversal in `hooksPath`**: if a repo/dependency name is copied into `hooksPath`, inject `../../..` to escape the intended hooks directory and point to a writable location. This is effectively a [path traversal](/hacktricks/pentesting-web/file-inclusion/overview) in Git config. 80 * **Overwrite another repo's `.git/config`**: if `ref` / branch / destination path controls where generated Git metadata is written, traverse into another workspace and replace its config. 81 * **Force intermediate directories to exist**: abuse clone destination controls so the backend creates paths such as `../../git_hooks` for you. 82 * **Ship executable hooks**: set the executable bit inside Git metadata so every clone writes the hook with mode `100755`: 83 ```bash 84 git update-index --chmod=+x pre-commit 85 ``` 86 * **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. 87 * **Race the config rewrite**: if the app restores `.git/config` right before invoking Git, keep overwriting it while triggering the Git action to win a [race condition](/hacktricks/pentesting-web/race-condition). 88 89 ### Buried bare repositories & repo-detection abuse 90 91 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.<sup>[[3]](#references)</sup><sup>[[5]](#references)</sup> 92 93 1. Create a nested bare repo. 94 2. Change `bare = true` to `bare = false`. 95 3. Add `core.worktree` and an execution directive such as `core.fsmonitor`. 96 4. If the service later `cd`s into that folder and runs `git status` / `git diff`, Git loads the buried config and executes your helper. 97 98 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. 99 100 ### Git argument injection and unsafe shell construction 101 102 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.<sup>[[4]](#references)</sup> 103 104 ```bash 105 # Vulnerable 106 git checkout $branch 107 git rm $path 108 109 # Safer 110 git checkout -- "$branch" 111 git rm -- "$path" 112 ``` 113 114 Interesting primitives to test:<sup>[[3]](#references)</sup> 115 116 * `--pathspec-from-file=<file>` with `git rm` to make Git read pathspecs from an arbitrary file and leak content via errors. 117 * Any workflow that joins argv into a **shell string** instead of using a real argument array. 118 * 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. 119 120 ### Symlink-based repository escape 121 122 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**:<sup>[[3]](#references)</sup> 123 124 ```text 125 repo/ 126 link -> ../../../etc/ 127 ``` 128 129 Then `repo/link/passwd` may resolve to `/etc/passwd`, and writes through that path may escape the repository boundary too.<sup>[[3]](#references)</sup> 130 131 Extra pivot points:<sup>[[3]](#references)</sup> 132 133 * **Blacklist bypass via repo-internal symlinks**: if the app blocks direct `.git/` reads with a prefix check, look for alternative paths such as `node_modules/pkg/.git/config` that resolve back to the real repo root through symlinks. 134 * **JGit `core.symlinks` abuse**: even if JGit ignores classic config-to-RCE directives, writing `symlinks = true` in `.git/config` can make the next pull/checkout materialize attacker-controlled symlinks, exposing broader filesystem paths or even other tenants' repositories if storage is shared. 135 136 ### Quick checklist when you find a Git-backed file primitive 137 138 * **File read**: inspect `.git/config` for credentials, remote URLs, internal paths, repo layout, and deployment metadata. 139 * **File write / append**: target `.git/config`, `.git/hooks/*`, or alternate repo markers (`HEAD`, `config`, `objects/`, `refs/`) to escalate into command execution or repo confusion. 140 * **File delete**: test whether removing `.git/HEAD` changes which repository Git discovers. 141 * **Path traversal / arbitrary folder creation**: look for generated clone destinations, dependency sync paths, worktrees, hook paths, and package install directories. 142 * **Package installation features**: local npm dependencies (`"pkg": "./"`, `file:`) may create symlinks under `node_modules/` that help bypass path blacklists and reach `.git/config` indirectly. 143 144 ## References 145 146 - [1] [holly-hacker/git-dumper – parallel fast /.git dumper](https://github.com/holly-hacker/git-dumper) 147 - [2] [Ebryx/GitDump](https://github.com/Ebryx/GitDump) 148 - [3] [The gift that keeps giving: Exploiting Git Integrations in Cloud Services](https://nopnop.pro/2026/06/17/exploiting-git-integrations-in-cloud-services/) 149 - [4] [Argument Injection Vectors (SonarSource)](https://sonarsource.github.io/argument-injection-vectors/) 150 - [5] [Git buried bare repos and fsmonitor abuses (justinsteven)](https://github.com/justinsteven/advisories/blob/main/2022_git_buried_bare_repos_and_fsmonitor_various_abuses.md) 151 - [6] [LookOut: RCE and internal access on Looker (Tenable)](https://www.tenable.com/blog/google-looker-vulnerabilities-rce-internal-access-lookout) 152 - [7] [TruffleHog documentation](https://github.com/trufflesecurity/trufflehog) 153 - [8] [Gitleaks documentation](https://github.com/gitleaks/gitleaks)