Your Deployed App Is Serving Its Own Source Code
The app works fine. Nothing looks broken. But anyone who requests /.git/config gets your entire repository.
73
Apps exposed
12,000+
Apps scanned
Full repo
Reconstructable
What this means
Every git repository has a .git directory at its root. This directory contains the entire history of the project: every file, every commit, every branch, every message. It contains the object database that stores the actual content. It is, quite literally, the repository.
When a web application is deployed with the .git directory included in the web root, and the server does not block requests to it, anyone can download it. Not just the current source code. The full history. Every secret that was ever committed and later removed is still in the object database. Every API key, every database password, every private configuration file that touched version control at any point is recoverable.
In Talon’s scan of 12,000+ recently launched applications, 73 had their .git directory accessible over HTTP. We confirmed exposure by requesting /.git/config and /.git/HEAD, both of which returned valid git metadata. That is enough to begin full reconstruction.
How attackers exploit this
The process is fully automated. Tools like git-dumper take a URL and reconstruct the entire repository locally. The tool starts with /.git/HEAD, follows references to branch heads, walks the commit graph, and downloads every object it finds. Within minutes, the attacker has a working local clone of the repository.
From there, the attacker runs the same secret-scanning tools that security teams use: trufflehog, gitleaks, or just git log -p with a few greps. They get:
| What they find | What they do with it |
|---|---|
| .env files in commit history | Extract API keys, database URLs, secrets that were "deleted" |
| Hardcoded credentials in source | Direct access to payment APIs, databases, third-party services |
| Internal API endpoints | Map the full attack surface, find unauthenticated routes |
| Business logic and auth code | Identify logic flaws, bypass auth checks, escalate privileges |
| Private configuration files | Infrastructure details, internal hostnames, deployment secrets |
Automated scanners sweep the internet for exposed .git directories continuously. This is not a theoretical risk. It is an active, ongoing collection effort.
Why this keeps happening
This is a deployment misconfiguration, not a code bug. The application works correctly. There are no errors. No tests fail. No monitoring triggers. The .git directory is just sitting there, served like any other static file, and nobody notices because nobody requests it during normal use.
The common causes are predictable:
Deploying the project root to a static host
Drag-and-drop deployment tools, rsync without exclusions, or scp of the entire directory. The .git folder comes along for the ride.
Misconfigured nginx or Apache
The default configuration for most web servers does not block dotfile directories. Unless you explicitly add a rule to deny requests to /.git, it will be served.
Docker COPY . without .dockerignore
COPY . /app in a Dockerfile copies everything, including .git. If the container serves files from /app, the git directory is exposed.
AI-generated deployment configs
Vibe-coded deployment scripts optimize for "it works." Excluding hidden directories from the web root is not part of that goal.
The pattern is the same every time: the deployment process copies everything, and nothing in the pipeline flags the inclusion of .git.
How to check
This takes thirty seconds.
01
Request /.git/config from your domain
Run: curl -s -o /dev/null -w "%{http_code}" https://yourdomain.com/.git/config. If you get a 200, your git directory is exposed. A 403 or 404 means it is blocked.
02
Request /.git/HEAD
Same test: curl -s https://yourdomain.com/.git/HEAD. If the response starts with "ref: refs/heads/" followed by a branch name, the git metadata is being served.
03
Check for directory listing
Request /.git/ directly. Some servers will return a full directory listing, making reconstruction even simpler. Others return 403 for the directory but still serve individual files inside it.
04
Run a scan
Talon checks for exposed .git directories as part of its surface scan. Free, no account required, results in about a minute.
How to fix it
The fix is server configuration. It takes minutes. Block all requests to /.git paths at the web server or CDN level.
Nginx
location ~ /\.git { deny all; return 404; }
Apache (.htaccess)
RedirectMatch 404 /\.git
Vercel / Netlify
These platforms do not serve .git directories by default. If you deploy through them, you are not affected by this specific issue.
Cloudflare
Create a WAF rule: URI Path contains "/.git" → Block. Takes effect immediately.
Docker
Add .git to your .dockerignore file. Rebuild and redeploy. Verify with the curl check above.
If your .git directory was accessible in production, assume every secret in your commit history is compromised. Rotate all API keys, database credentials, and tokens that appear anywhere in your git history. Not just the current files. The history.
The takeaway
Serving your .git directory is equivalent to making your entire repository public. Every file, every commit, every secret that was ever checked in. The application works fine the entire time. There is no error, no warning, no visible symptom.
73 out of 12,000 recently launched apps had this exact exposure. The fix is a single server configuration rule. The check is a single curl command. There is no reason for this to stay open longer than the time it takes to read this sentence and paste a config block.
Run a free surface scan
Talon checks for exposed .git directories, leaked credentials in your frontend and public repositories, accessible environment files, and other deployment misconfigurations. Passive, read-only, no account required.