Exposed .git Directory
An exposed .git directory is a version-control folder left reachable over HTTP, letting anyone download the repository internals and reconstruct your full source code, commit history, and any secrets committed along the way.
A web server is supposed to serve a built application, not the toolbox used to build it. When the hidden .git folder ships to production by accident, that line blurs: a single curl request to /.git/config can be the difference between a private codebase and a fully reconstructable one. This is one of the most common high-impact findings in external attack surface management because it is silent, trivially exploitable, and almost always the result of a deployment shortcut rather than a code flaw.
Reviewed by Aakash Harish
Security Research Contributor, Legba
Reviewed 2026-05-28 · Updated 2026-05-28
What it is
Git stores everything it knows about a repository inside a hidden .git directory: the HEAD file pointing at the current branch, a config file describing remotes, a packed object store under objects/, reference pointers under refs/ and packed-refs, the staging index, and the reflog under logs/. When a project is deployed by running 'git clone' or 'git pull' directly in the web root, or by copying the entire working tree (including .git) onto the server, that metadata folder becomes reachable over HTTP. Because every blob, tree, and commit object is stored in a content-addressable, deterministically named layout, an attacker who can read those files can rebuild the working tree exactly, even when directory listing is disabled.
What you stand to lose here is not a single file but the entire intellectual and security foundation of the application. Once the repository is dumped, an attacker reads your source the way your own engineers do: they trace authentication logic, find unguarded endpoints, and locate the hardcoded database passwords, API keys, and signing secrets that developers committed and later thought they had removed, forgetting that git keeps deleted content in history forever. CWE-527 classifies this as exposure of a version-control repository to an unauthorized control sphere, and the leaked metadata alone can reveal usernames, internal file paths, and IP addresses. The practical consequence is a fast escalation path from passive information disclosure to credential theft, database compromise, and full account takeover, with the breach often beginning before any logging on the application even fires.
At a glance
How attackers find and exploit it
- Enumerate candidate hosts with mass recon (certificate transparency logs, DNS brute force, port scans) and queue every web origin for a content-discovery sweep.
- Request /.git/HEAD and /.git/config on each origin; a 200 response containing a 'ref:' line or a '[core]' INI section is a near-certain confirmation that the repository is exposed.
- Pull the low-hanging metadata first: /.git/config often discloses the remote origin URL (sometimes with embedded credentials), and /.git/logs/HEAD reveals committer names, emails, and the commit graph.
- Run an automated dumper such as git-dumper or GitTools to walk refs, packed-refs, the index, and the loose object store, then recursively fetch every referenced object even when Apache or Nginx directory listing is turned off.
- Reconstruct the working tree with 'git checkout' from the recovered objects, then grep the source and full history for secrets (API keys, .env values, private keys) and for exploitable application logic to chain into deeper compromise.
How to detect it on your surface
- Inventory every public web origin (apex domains, subdomains, load balancers, legacy hosts) and request /.git/HEAD and /.git/config against each one, treating any non-404 response as a finding to investigate.
- Sweep for sibling version-control metadata at the same time, including /.svn/entries, /.hg/, and /.bzr/, since the same deployment mistake exposes all of them.
- Audit your deployment pipeline: confirm production artifacts are built from a checkout that excludes .git, rather than a raw 'git clone' or 'git pull' into the document root.
- Search web server configuration for an explicit deny rule on dot-git paths and verify it actually returns 403/404 by testing in a staging environment that mirrors production.
- Review reverse proxy and CDN rules, because an origin-level block can be bypassed if a caching tier or alternate vhost serves the path differently.
Detection signals
- /.git/HEAD returns HTTP 200 with a body like 'ref: refs/heads/main' or a 40-character commit hash.
- /.git/config returns 200 with INI sections such as '[core]', '[remote "origin"]', and a 'url =' line.
- A 403 Forbidden (rather than 404 Not Found) on /.git/ indicates the directory physically exists even though listing is blocked, meaning individual files may still be fetchable.
- /.git/logs/HEAD or /.git/index returns binary or structured content, and /.git/objects/pack/ serves .pack and .idx files when directory listing is enabled.
Validate before you report
- Fetch /.git/config and /.git/HEAD and confirm the byte content is genuine git metadata (valid INI structure and a real ref or hash), not a custom error page returning 200.
- Retrieve a single loose object referenced by HEAD and inflate it with zlib to confirm it decompresses into a valid git object header (e.g. 'commit', 'tree', or 'blob' plus a length), proving the object store is live.
- Attempt a controlled, scoped dump of refs and a small number of objects, then run 'git fsck' or 'git checkout' on the recovered repository to prove the source tree actually reconstructs.
- Capture the evidence (HTTP responses, recovered file names, and a redacted snippet of recovered source) and note the exact commit reachable, so the finding is provably a true positive rather than a guessed signature.
What looks like this but isn't
- A wildcard or SPA catch-all route that returns 200 with the app's HTML for every path, including /.git/HEAD, is not an exposure; verify the response is real git metadata, not the index page.
- A directory literally named 'git' (a docs folder, a UI component, or a vanity path) is unrelated; the finding requires the dot-prefixed .git internals such as HEAD, config, and objects to be served.
Remediation
- Immediately block all access to dot-git paths at the web server: in Apache use a 'Require all denied' or LocationMatch rule for (^|/)\.git, in Nginx add 'location ~ /\.git { deny all; return 404; }', and apply the equivalent request-filtering rule in IIS.
- Remove the .git directory from the production document root entirely so a configuration regression cannot re-expose it.
- Rebuild your deployment to ship only build artifacts (for example via CI/CD, rsync with excludes, or container images), never by running 'git clone' or 'git pull' in the web root.
- Treat every secret discoverable in the repository or its history as compromised: rotate database credentials, API keys, tokens, and private keys, and purge them from git history with a tool like git filter-repo so future leaks reveal nothing.
- Add a deny rule for sibling VCS metadata (.svn, .hg, .bzr) and for other sensitive dotfiles (.env, .htpasswd) using the same mechanism.
- Verify the fix in staging and production by confirming /.git/HEAD and /.git/config return 404, then add an automated check to your pipeline so the regression cannot ship again.
Operational checklist
- Maintain a continuously updated inventory of every internet-facing web origin and probe all of them for VCS metadata on a recurring schedule, not just at deploy time.
- Enforce, via a deny rule in a shared base server configuration, that dotfiles and VCS directories are never served, so new sites inherit the protection by default.
- Gate releases with a CI/CD step that fails the build if a .git directory would be included in the deployed artifact.
- Run secret scanning (for example gitleaks or trufflehog) across repositories and history so committed credentials are caught before they can leak through any channel.
- Operate a credential rotation runbook so that any confirmed source-code or metadata exposure triggers prompt revocation and reissue of affected secrets.
- Re-test after every infrastructure or proxy change, since CDN, load-balancer, and vhost reconfiguration can silently reopen a previously closed path.
What to do next
An exposed .git directory is a quiet, high-severity gift to attackers: it converts your deployment shortcut into their reconstruction of your source and secrets. The work your security team actually needs is not another raw scanner alert but a confirmed, evidenced finding it can act on today. Start now: request /.git/HEAD and /.git/config across your full external footprint, and if either returns live git metadata, block the path, pull .git out of the web root, and rotate every secret in that repository's history before someone else reads it first.
Methodology
Each finding-type guide is built from Legba Recon's real detection and validation logic, reviewed by a named security contributor, and cited against primary sources such as OWASP, CISA, NIST, and MITRE. We update pages when the underlying guidance changes. See our contributors and company.
FAQs.
References.
- 01
- 02
- 03
- 04
- 05
