← Attack pathsexposed .git folders leak your entire source code

exposed .git folders leak your entire source code

$git-dumper https://site/.git/ loot/

your web root probably has a time machine attached to it

here's a fun one. if you deploy your site by running git pull on the server, there's a decent chance you've got a .git folder just sitting in your web root, publicly reachable, holding your entire commit history. every file you ever committed. every secret you ever "removed" in a later commit. all of it. still there. git doesn't forget, it just moves on.

this isn't some exotic attack. it's one of the most common misconfigs on the internet because it's the natural result of the laziest possible deploy method: ssh in, git pull, done. nobody thinks about the fact that the .git directory came along for the ride and is now sitting right next to your index.html, fully downloadable by anyone who asks nicely.

how someone finds this on YOUR site

the check is embarrassingly simple. anyone (including you, right now, on your own domain) can hit:

https://yoursite.com/.git/HEAD

if that returns actual git data instead of a 404, your repository is exposed. that's the whole test. no scanning tools required, just a browser and two seconds.

what the "attack" actually does (so you understand your exposure)

a tool like git-dumper automates rebuilding a full local copy of your repo from that exposed folder:

git-dumper https://site/.git/ loot/

it walks the git object structure the same way your own git client does when you clone a repo, just pulling the raw files over http instead of a proper git protocol. the result in loot/ is a working copy of your project, including old commits, old branches, and anything that ever got checked in and later "deleted."

from there, finding secrets is just grep:

grep -rniE 'password|secret_key' loot/

this searches the entire rebuilt history, not just the current files, for anything that looks like a credential. this is the part people get wrong: they think deleting a secret from the current version of the code removes it. it doesn't. the commit where it existed is still in history forever unless you specifically rewrite that history. deleting the file just hides it from the file explorer, not from the timeline.

the fix: block it at the web server

step one, immediately, is to make sure your web server refuses to serve dotfiles like .git at all. for nginx:

location ~ /\.git { deny all; return 404; }

then test the config and reload:

nginx -t && systemctl reload nginx

apache users want the equivalent in your vhost or .htaccess, denying access to any path starting with .git. this is a five minute fix and there's genuinely no reason not to have it on every single server you run, even ones you're "sure" don't have git in the web root. defense in depth means blocking it even when you think it doesn't apply.

the actual fix: stop deploying with git pull

blocking the folder is a patch, not a solution. the real problem is that your deploy method puts source control metadata into a public-facing directory in the first place. the better long-term move is to stop deploying by pulling a live repo onto the server at all. build an artifact (a docker image, a zip, a compiled bundle, whatever fits your stack) in a CI pipeline or locally, and ship that artifact to the server. the server never sees a .git folder because there isn't one to see. this also gets you cleaner rollbacks and a build process you can actually audit, so it's not even purely a security upgrade, it's just a better way to deploy.

rotate anything that was ever committed

if you find real credentials in that grep output, the fix isn't deleting the line and committing again. the secret is already burned. rotate it: new api key, new db password, new secret_key, whatever it is. treat "it was in git history at any point" as equivalent to "it's public." because functionally, if your .git folder was ever exposed even briefly, it is.

the takeaway

check your own sites right now: visit /.git/HEAD on everything you run. if it responds with git data, block it at the server level today, then plan a real fix by moving to artifact based deploys. and go grep your own history for secrets while you're at it, because "i deleted it in the next commit" was never as safe as it felt.

watch the reel ↗
the weekly drop

one command a week that makes you harder to hack.

a single tool, explained in plain english, every week. straight to your inbox.

no spam. one email a week. unsubscribe anytime.