Mercurial hgweb Separates Authentication from Authorization
Mercurial's web interface, hgweb, can publish repositories and support HTTP access. It does not perform authentication itself. The web server in front of it prompts for and validates users, then Mercurial applies authorization settings for the authenticated identity. A deployment that treats hgweb as a complete access-control system can expose repositories without realizing that the identity layer was never supplied.
On 2026-11-11 at 08:46:40 +08:00, title="Mercurial" returned 664 ZoomEye matches with page 1, page size 1, and sub_type=all. A query for app="Mercurial" returned 11 matches at 08:46:39 +08:00. The links are the title query and the application query.
The title and application counts differ by a large factor. A title can appear in documentation, project pages, and repository indexes. The application fingerprint is narrower but still does not prove that a repository is readable or writable. Both observations are inventory hints only.
The web server owns identity
The Mercurial configuration documentation is explicit that the web server does no authentication. It performs authorization for an authenticated user based on the web configuration. The allow_read, deny_read, allow_push, and deny_push settings determine what the repository interface permits for that identity.
This leads to two common failure patterns:
- The web server allows anonymous access and hgweb has no restrictive read list.
- The web server authenticates everyone through a shared account, so hgweb cannot distinguish developers from contractors.
The first publishes the repository by design or by accident. The second collapses individual accountability into one identity. Neither is solved by changing the Mercurial title or adding a generic login page.
Review repository visibility and push paths
Start with the repository index and the direct URL. Confirm whether an anonymous user can see the repository list, browse history, clone a repository, or push. Then repeat with a normal user and a repository administrator. Record the web server authentication method, the identity passed to hgweb, and the exact web configuration in effect.
A denied read should not be inferred from a hidden repository name. If the repository is served through hgwebdir, the configuration can hide it from the list while direct access may follow a different path. Test the direct route as well as the index.
Push access deserves its own test. A read-only public repository may be a legitimate design. A repository whose web interface accepts anonymous push is a different problem. Verify both the advertised URL and the underlying web server configuration, then test an actual push with a non-privileged account.
If the repository is behind a proxy, check header handling. A proxy that passes a user header from the client can create a false identity. A proxy that sets the header only after successful authentication can provide a usable identity, but the web server still needs a rule that treats missing or malformed identity as anonymous or denied.
Use the counts as discovery
The 664 title matches and 11 application matches do not tell you how many repositories are public. They are not an exposure threshold and should not be used to rank organizations. A site can match the title and intentionally serve only a public landing page. A self-hosted repository can avoid the word Mercurial in its title.
For each confirmed deployment, record the exact host, the web server product, the authentication method, the repository visibility, and the tested push behavior. Store a negative test result too. Knowing that anonymous push is denied is as important as knowing that anonymous read is allowed.
The practical control
Treat hgweb as an application behind an identity-aware reverse proxy. Make the proxy own authentication, make Mercurial own repository authorization, and make the repository owner review both. A safe deployment can explain why a user is authenticated, what the user may read, and what the user may write. A public repository can fit that model. An unidentified push path cannot.
Top comments (0)