Skip to content

git-receive-pack info/refs advertisement skips the visibility gate, leaking private repo ref metadata #116

Description

@beardthelion

Summary

git_info_refs (crates/gitlawb-node/src/api/repos.rs) serves both the git-upload-pack and git-receive-pack ref advertisement off one anonymous route, but the read-visibility gate was wrapped in if service == "git-upload-pack". An anonymous

GET /{owner}/{repo}.git/info/refs?service=git-receive-pack

against a private repo returned its branch/tag names and commit tips, bypassing the read gate the upload-pack path enforces. This is the git-transport sibling of #112 (GraphQL refUpdates) and #114 (REST events feed): the same private ref-metadata, a different egress.

Where

  • crates/gitlawb-node/src/api/repos.rsgit_info_refs, the visibility check scoped to a single service.
  • The route is on the optional_signature group, so it is reachable unauthenticated.

Impact

For any private repo whose owner-DID slug an attacker can guess or enumerate, an unauthenticated request discloses its branch/tag names, commit SHAs, and existence, over plain git smart-HTTP. The in-code comment claimed the receive-pack path "is authorized separately on the POST" — true for the push itself, but the advertisement discloses the same metadata the read path withholds.

Fix

Run visibility_check(.., "/") for the advertisement regardless of service (deny -> 404, existence-hiding). Because the advertisement is then gated for both services, the git-remote-gitlawb helper must authenticate its own requests, so it now signs the Phase-1 advertisement GET and the Phase-2 pack POST for both services over path_and_query when an identity keypair is present (public repos stay anonymous). This also repaired a pre-existing break where a repo's owner could not fetch their own private repo, because the upload-pack POST was sent unsigned.

A fix is implemented and verified in branch fix/gate-receive-pack-advertisement (PR to follow). Verified by execution: the anonymous receive-pack advertisement now returns 404 (was a 200/served leak); a live git clone gitlawb:// of a private repo succeeds for the owner and is denied (404, no content) for anonymous and non-owner callers; node-side and seam tests cover both services.

Metadata

Metadata

Assignees

No one assigned

    Labels

    crate:git-remotegit-remote-gitlawb — the git remote helpercrate:nodegitlawb-node — the serving node and REST APIkind:securityVulnerability fix or hardeningsev:highMajor break or real security/trust risk, no easy workaroundsubsystem:apiNode REST API request/response surfacesubsystem:visibilityPath-scoped visibility and content withholding

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions