RoastMyOpsec

Vulnerabilities

Exposed .hg vs .git on Production Websites

September 23, 2023

Exposed .hg vs .git on production websites is the same incident class in two DVCS costumes. A public /.git/HEAD (and the objects beside it) can donate source, history, and sometimes secrets that were committed. A public /.hg directory is Mercurial store metadata — dirstate, store, requires — that can donate the same kind of inventory. Neither belongs next to index.html. robots.txt Disallow is not a lock. RoastMyOpsec probes /.git/HEAD with a bounded GET looking for a signature. It does not currently score /.hg, does not dump repositories, and does not reconstruct working copies.

The practical difference

Git leftovers show up when a deploy copies the whole repo instead of an export. Mercurial leftovers show up on shops that never migrated, or on a forgotten vhost that still uses hg. .svn is a third VCS costume. .env is a secrets channel. Treat all as publish denylist plus CDN deny.

A 404 on /.hg/requires is not proof the store is gone from another prefix or an old clone path.

How to choose what to strip

CI: publish an artifact that never contains .git, .hg, .svn, or .bzr. CDN: deny those prefixes even if CI is perfect. Server: never clone into the document root. Staging hostnames that are guessable get the same rules. Pair with dump.sql if the same zip also held a database.

LeftoverTypical leakRoast todayTakeaway
/.git/HEADSource and historyBounded signature GETIncident-class; deny the tree
/.hg/Mercurial store metadataNot scored; deny anywaySame class as git
/.svn/Working-copy metadataNot scored; deny anywaySee .svn vs .git
/.envLive secretsBounded signature GETSee .git vs .env

When Mercurial still wins (off the public origin)

A private hg server is fine. A clone in the web root is not. Git still wins as the common leak in 2026. Missing .hg on a Node site is healthy.

What the roast can prove

A .git/HEAD signature can surface. .hg is not a scored path. Confirm a deny at the edge. Pair with directory listing if autoindex still lists .hg.

Common mistakes

The first mistake is stripping only .git because 'we use GitHub now' while an old host still has an hg clone.

The second mistake is Disallow: /.hg and calling it access control.

The third mistake is treating a roast miss on .hg as proof the store 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 now

FAQ

Is a public .hg folder a vulnerability?
Yes — it is an information-leak class, same family as a public .git. Deny it at the edge and stop deploying working copies.
Does RoastMyOpsec fetch .hg?
Not as a scored path today. It does probe .git/HEAD. Deny both prefixes anyway.
Will the scanner dump my Mercurial repo?
No. Bounded GETs and signatures only. No recursive dump, no exploit payload.

Sources

Related guides