From be06e36623c8f7fd3b15e00dc204bc430812eeab Mon Sep 17 00:00:00 2001 From: Wael Nasreddine Date: Wed, 11 Feb 2026 10:31:15 -0800 Subject: [PATCH] security: harden the narinfo route pattern The narinfo hash was updated in #840 to reflect the upstream definition in NixOS/nix#15004 and so the server should only allow narinfo requests that match this pattern. --- pkg/server/security_test.go | 11 ++--------- pkg/server/server.go | 8 ++------ 2 files changed, 4 insertions(+), 15 deletions(-) diff --git a/pkg/server/security_test.go b/pkg/server/security_test.go index 64ce3d7f..c0c86f82 100644 --- a/pkg/server/security_test.go +++ b/pkg/server/security_test.go @@ -97,13 +97,6 @@ L: expectedStatus: http.StatusNotFound, // Not found upstream, but reached it shouldReachUpstream: true, }, - { - name: "Valid 52-char narinfo hash", - method: http.MethodGet, - path: "/1lid9xrpirkzcpqsxfq02qwiq0yd70chfl860wzsqd1739ih0nri.narinfo", - expectedStatus: http.StatusNotFound, - shouldReachUpstream: true, - }, { name: "Invalid hash length (31 chars)", method: http.MethodGet, @@ -121,8 +114,8 @@ L: { name: "Path traversal attempt (alphanumeric but malicious)", method: http.MethodGet, - path: "/abcdefghijklmnopqrstuvwxyz0123456789.narinfo", // 44 chars - expectedStatus: http.StatusBadRequest, // Rejected by helper.IsValidHash + path: "/aeou456789abcdfghijklmnpqrsvwxy.narinfo", // contains all 4 chars not allowed aeou + expectedStatus: http.StatusNotFound, shouldReachUpstream: false, }, { diff --git a/pkg/server/server.go b/pkg/server/server.go index e2d86555..f1dc2e17 100644 --- a/pkg/server/server.go +++ b/pkg/server/server.go @@ -29,6 +29,7 @@ import ( "github.com/kalbasit/ncps/pkg/cache/upstream" "github.com/kalbasit/ncps/pkg/helper" "github.com/kalbasit/ncps/pkg/nar" + "github.com/kalbasit/ncps/pkg/narinfo" "github.com/kalbasit/ncps/pkg/storage" ) @@ -36,7 +37,7 @@ const ( routeIndex = "/" routeNar = "/nar/{hash:[a-z0-9]{32,52}}.nar" routeNarCompression = "/nar/{hash:[a-z0-9]{32,52}}.nar.{compression:*}" - routeNarInfo = "/{hash:[a-z0-9]{32,52}}.narinfo" + routeNarInfo = "/{hash:" + narinfo.HashPattern + "}.narinfo" routeCacheInfo = "/nix-cache-info" routeCachePublicKey = "/pubkey" @@ -305,11 +306,6 @@ func (s *Server) getNixCachePublicKey(w http.ResponseWriter, r *http.Request) { func (s *Server) getNarInfo(withBody bool) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { hash := chi.URLParam(r, "hash") - if !helper.IsValidHash(hash) { - http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest) - - return - } ctx, span := tracer.Start( r.Context(),