Exposed .git repository

The site's .git directory is reachable over HTTP. Anyone can reconstruct the full source repository, including configuration files, credentials and every past commit.

Do this: Block /.git at the server, then redeploy without it. The whole repository, including deleted files, old credentials and commit history, can be reconstructed from it.
PassNo exposed .git repository was found.
CriticalThe .git directory is publicly accessible.

The fix, in one snippet

Example to adapt nginx, then purge it from the deploy
location ~ /\.git { deny all; return 404; }
# and stop shipping it:
rsync -a --exclude='.git' ./ server:/var/www/

Illustrative values. Change the paths, hostnames and options to match your own site before using it.

The sections below explain what is tested, why it matters and the alternatives.

What we test

Scan.now requests /.git/HEAD. A finding requires an HTTP 200 whose body begins with ref: refs/heads/ or consists of a 40- or 64-character hexadecimal commit hash; an HTML "not found" page returned with status 200 does not match. To rule out a coincidental file, it then requests /.git/config and confirms that it contains a [core] section. Scan.now stops there: it does not enumerate refs, download objects or reconstruct the repository, and it never stores what it retrieves beyond the match itself. The finding is rated critical because reconstruction from these two files is fully automated in public tools and needs no further weakness. Related exposures are covered by exposed-env-file and exposed-backup-files.

Why it matters

An exposed .git directory is a complete copy of your codebase for anyone who asks. Tools such as git-dumper walk from HEAD through the refs and packed objects, whose paths are predictable from their hashes, and rebuild a working tree even with directory listing disabled. The result includes configuration files with database passwords and API keys, the logic of every authentication and authorisation check, and the full commit history, so a secret that was committed and later "removed" is still there. .git/config frequently contains a remote URL with an embedded access token. From source, an attacker moves quickly to SQL injection or logic flaws they can now read rather than guess. Internet-wide scans for /.git/HEAD run constantly, so an exposed repository is usually found within days. The exposed files guide describes the pattern and the other files that travel with it.

How to fix it

The durable fix is to deploy build artifacts, not a git checkout, into the web root. Until then, block every dotfile except .well-known at the server. nginx:

location ~ /\.(?!well-known/) {
    deny all;
    return 404;
}

Apache 2.4:

<DirectoryMatch "/\.git">
    Require all denied
</DirectoryMatch>
RedirectMatch 404 /\.(?!well-known/)

Cloudflare: a WAF custom rule with the expression (starts_with(http.request.uri.path, "/.git")) and action Block stops requests at the edge, but apply the origin rule as well. After blocking, treat the incident as a disclosure: rotate every credential in the repository and its history, check the access log for earlier requests to /.git/, and consider whether the source itself reveals anything that needs fixing:

grep -c '/\.git/' /var/log/nginx/access.log

Verify the fix returns 404 for /.git/HEAD and /.git/config, then re-run the website scanner.

Where this fits

Exposed .git repository is check 2 of 14 that the website vulnerability scanner runs under exposed files and information disclosure, ordered the way they are worth fixing. That ordering is the point: Fixing this one while the check above it still fails buys less than it looks like.

Fix this one first

Above it in the same category sits Exposed .env configuration file (critical), where a .env configuration file is served from the web root. An attacker who has that does not need this, so it is the better use of the same hour.

What fixing this still leaves open

Exposed .git repository closes one route in. Immediately below it: Exposed backup or archive files, where a backup archive, database dump or editor backup copy of a configuration file is downloadable from the web root, exposing source code, credentials and user data; Exposed phpinfo() page, where a phpinfo() page is publicly reachable; Directory listing enabled, where the web server generates an index of files for a directory that has no index page, exposing every file in it, including ones that are not linked from anywhere.

Found in the same scan

The website vulnerability scanner reports this alongside checks from other categories that are at least as serious, including Certificate chain and hostname validation, where the certificate presented for this hostname did not validate: The chain does not reach a trusted root, an intermediate is missing, the name does not match, or the certificate is self-signed or expired, and HTTPS is available, where the site could not be reached over HTTPS on port 443, or the TLS handshake failed. A single run of website vulnerability scanner answers all of them at once.

Prompt for an AI Hand this check to an assistant Sign in to copy it
The first few lines
You are a senior web engineer. I ran a security and SEO scanner against my site and it reported the finding below. Fix it properly rather than suppressing the symptom.

Finding: Exposed .git repository (critical severity)
Scanner check id: exposed-git-directory
19 more lines, including the evidence and the exact fix

The rest of this prompt names the pages and line numbers we found the problem on, the configuration to change, and the constraints a good answer has to respect. It is free, it just needs an account so the work is not scraped wholesale.

Sign in with Google

Signing in is free and takes one click. We store your email address and nothing else.

References

  1. git-dumper (demonstrates reconstruction from an exposed .git)
  2. OWASP WSTG: Review Old Backup and Unreferenced Files
  3. CWE-538: Insertion of Sensitive Information into Externally-Accessible File or Directory

Related guides