Vulnerabilities
.gitmodules vs .git/HEAD on Production Origins
January 3, 2024
.gitmodules vs .git/HEAD on a production origin is a submodule inventory file versus proof the git directory is on the CDN. A reachable /.git/HEAD with a ref: signature is a VCS dump class finding — the roast already scores it. A reachable .gitmodules donates submodule URLs and paths, sometimes including private remotes. Serving either is the same class of miss as leftover VCS crumbs next to index.html. RoastMyOpsec may not fetch .gitmodules today. Still deny it at the edge. Do not Disallow git paths in robots.txt; that advertises the working copy.
The practical difference
.git/HEAD is the pointer into a full history tree if objects are also public. .gitmodules is a small INI map of extra remotes. History is worse. The map is still a map. Neither belongs on a static host.
GitHub Pages documents that submodule URLs in .gitmodules should be https for builds it can fetch — that is a Pages concern, not a reason to serve .gitmodules from your marketing bucket.
How to choose based on what you shipped
If .git/HEAD hit: deny the .git prefix at the CDN, treat it as a source-and-history incident, rotate secrets that may have been in that repo. If only .gitmodules is in the artifact: still take it off the origin and stop publishing the git working copy. Fail CI when .git or .gitmodules appear in a static export.
| Option | When it wins | Watch-out | Takeaway |
|---|---|---|---|
| /.git/HEAD | Never on the CDN | VCS dump signature | Roast signatures this path today |
| /.gitmodules | Never on the CDN | Submodule URLs and paths | Same class of miss; deny the name |
| Submodules in a private repo | Code sharing you intended | Do not deploy the working copy as the site | Keep git metadata off the origin |
| robots.txt Disallow | Not for .git | Treasure map | Edge deny the prefix |
When each git file wins (never as a public object)
.git/HEAD wins only inside a real git directory on a machine or in a host you do not publish. .gitmodules wins in a private repository that actually uses submodules. Neither wins next to index.html.
If directory listing is on, the map gets louder. Turn listing off and still deny VCS names at the edge.
Common mistakes
The first mistake is deploying the git working copy because the build output lived in the same folder.
The second mistake is blocking /.git/HEAD and still serving .gitmodules from the artifact root.
The third mistake is Disallowing /.git in robots.txt and calling the dump closed.
What a URL roast can prove
Bounded GET to /.git/HEAD looking for a ref: signature. .gitmodules is not a scored path today. Still deny it. No recursive object walk, no history dump, no exploit payload. A miss on HEAD is not proof every git metadata file is gone.
Free audit the URL you own
RoastMyOpsec is a defensive public-surface roast: headers, cookies, sensitive paths, and more — no exploit payloads. Start with the free audit, then open the vault if the blurred findings look expensive.
Free audit nowFAQ
- Is a public .gitmodules a vulnerability?
- It is an information leak and a sign the git tree hitchhiked onto the origin. Remove it, deny git metadata at the edge, and check whether .git/HEAD is also reachable.
- Does RoastMyOpsec fetch .gitmodules?
- Not as a scored path today. It does probe /.git/HEAD. Deny .gitmodules at the CDN anyway. Same class of miss.
- Is .gitmodules worse than .git/HEAD?
- Usually no. HEAD plus objects is the history dump. .gitmodules is the submodule map. Fix both. Do not debate the trophy.
Sources
Related guides
Vulnerabilities
Exposed .git vs .env on Production WebsitesVulnerabilities
robots.txt Disallow vs Access Control for Hidden PathsVulnerabilities
Dockerfile vs package.json on Production Origins