From 927271ff8c05e3f1e068265c569672b99f6abbbb Mon Sep 17 00:00:00 2001 From: Andrew Nesbitt Date: Tue, 12 May 2026 20:34:53 +0100 Subject: [PATCH] Bump registries to v0.6.0 and gate client with safehttp PURLs can carry a repository_url qualifier that NewFromPURL and BulkFetchPackages use as the fetch base URL. Wrap the underlying client with WithSafeHTTP so loopback, RFC1918, link-local and similar targets are refused at dial time. --- go.mod | 2 +- go.sum | 4 ++-- registries.go | 6 +++++- registries_test.go | 30 ++++++++++++++++++++++++++++++ 4 files changed, 38 insertions(+), 4 deletions(-) create mode 100644 registries_test.go diff --git a/go.mod b/go.mod index 631b1cb..f4abd0b 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.25.6 require ( github.com/ecosyste-ms/ecosystems-go v0.1.1 github.com/git-pkgs/purl v0.1.12 - github.com/git-pkgs/registries v0.5.1 + github.com/git-pkgs/registries v0.6.0 github.com/git-pkgs/vers v0.2.5 ) diff --git a/go.sum b/go.sum index 77cb96e..0fcc5f3 100644 --- a/go.sum +++ b/go.sum @@ -13,8 +13,8 @@ github.com/git-pkgs/pom v0.1.4 h1:C6st+XSbF75eKuwfdkDZZtYHoTcaWRIEQYar5VtszUo= github.com/git-pkgs/pom v0.1.4/go.mod h1:ufdMBe1lKzqOeP9IUb9NPZ458xKV8E8NvuyBMxOfwIk= github.com/git-pkgs/purl v0.1.12 h1:qCskrEU1LWQhCkIVZd992W5++Bsxazvx2Cx1/65qCvU= github.com/git-pkgs/purl v0.1.12/go.mod h1:ofp4mHsR0cUeVONQaf33n6Wxg2QTEvtUdRfCedI8ouA= -github.com/git-pkgs/registries v0.5.1 h1:UPE42CyZAsOfqO3N5bDelu28wS4Ifx/aOj0XZS4qYeI= -github.com/git-pkgs/registries v0.5.1/go.mod h1:BY0YW+V0WDGBMuDR2aSMR3NzOPFK4K+F3j6+ch+cq3M= +github.com/git-pkgs/registries v0.6.0 h1:ttQC8via9XAoLk9vqysf0K7uWl1bAyHPBWRBavRpAqs= +github.com/git-pkgs/registries v0.6.0/go.mod h1:BY0YW+V0WDGBMuDR2aSMR3NzOPFK4K+F3j6+ch+cq3M= github.com/git-pkgs/spdx v0.1.3 h1:YQou23mLfzbW//6JlHUuc5x1P5VNIIDSku5gvauf86I= github.com/git-pkgs/spdx v0.1.3/go.mod h1:4HGGWyC8tg4DjOhrtBTYl4Lu+5i2BFuauGX8zcVcYPg= github.com/git-pkgs/vers v0.2.5 h1:tDtUMik9Iw1lyPHdT5V6LXjLo9LsJc0xOawURz7ibQU= diff --git a/registries.go b/registries.go index e17bd71..64a1b74 100644 --- a/registries.go +++ b/registries.go @@ -7,6 +7,7 @@ import ( "github.com/git-pkgs/purl" "github.com/git-pkgs/registries" _ "github.com/git-pkgs/registries/all" + "github.com/git-pkgs/registries/client" "github.com/git-pkgs/vers" ) @@ -21,7 +22,10 @@ func NewRegistriesClient() *RegistriesClient { } func newRegistriesClient(userAgent string) *RegistriesClient { - c := registries.DefaultClient() + // PURLs may carry an attacker-supplied repository_url qualifier that + // NewFromPURL/BulkFetchPackages will fetch from; gate the client's + // transport so loopback/RFC1918/link-local targets are refused. + c := registries.NewClient(client.WithSafeHTTP()) c.UserAgent = userAgent return &RegistriesClient{client: c} } diff --git a/registries_test.go b/registries_test.go new file mode 100644 index 0000000..bb9dde1 --- /dev/null +++ b/registries_test.go @@ -0,0 +1,30 @@ +package enrichment + +import ( + "context" + "net/http" + "net/http/httptest" + "net/url" + "sync/atomic" + "testing" +) + +func TestRegistriesClientBlocksLoopbackRepositoryURL(t *testing.T) { + var hits int32 + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + atomic.AddInt32(&hits, 1) + w.WriteHeader(http.StatusOK) + })) + defer srv.Close() + + c := NewRegistriesClient() + purl := "pkg:npm/lodash?repository_url=" + url.QueryEscape(srv.URL) + + _, err := c.GetVersions(context.Background(), purl) + if err == nil { + t.Fatalf("expected safehttp to refuse loopback %s, got nil error", srv.URL) + } + if n := atomic.LoadInt32(&hits); n != 0 { + t.Fatalf("loopback server received %d requests; safehttp gate did not block dial", n) + } +}