From ecbeba8e677383f5117b109118d14291a8f23bc4 Mon Sep 17 00:00:00 2001 From: Zoltan Papp Date: Wed, 2 Sep 2026 12:36:03 +0200 Subject: [PATCH] [management] Fix geolocation panics (#7382) * [management] Return errors instead of panicking on malformed geolocation inputs * [management] Reject empty date suffix in geolocation database filename --- management/server/geolocation/database.go | 7 +++++++ management/server/geolocation/geolocation.go | 6 +++++- management/server/geolocation/utils.go | 7 ++++++- 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/management/server/geolocation/database.go b/management/server/geolocation/database.go index 97ab398fb..71106d5cd 100644 --- a/management/server/geolocation/database.go +++ b/management/server/geolocation/database.go @@ -3,6 +3,7 @@ package geolocation import ( "context" "encoding/csv" + "fmt" "io" "os" "path" @@ -21,6 +22,8 @@ const ( geoLiteCitySha256ZipURL = "https://pkgs.netbird.io/geolocation-dbs/GeoLite2-City-CSV/download?suffix=zip.sha256" geoLiteCityMMDB = "GeoLite2-City.mmdb" geoLiteCityCSV = "GeoLite2-City-Locations-en.csv" + + geonamesCsvFields = 14 ) // loadGeolocationDatabases loads the MaxMind databases. @@ -160,6 +163,10 @@ func loadGeonamesCsv(filepath string) ([]GeoNames, error) { if index == 0 { continue } + if len(record) < geonamesCsvFields { + return nil, fmt.Errorf("geonames csv record %d has %d fields, want at least %d", index, len(record), geonamesCsvFields) + } + geoNameID, err := strconv.Atoi(record[0]) if err != nil { return nil, err diff --git a/management/server/geolocation/geolocation.go b/management/server/geolocation/geolocation.go index 0af3ce2f6..b8a064a33 100644 --- a/management/server/geolocation/geolocation.go +++ b/management/server/geolocation/geolocation.go @@ -242,7 +242,11 @@ func getDatabaseFilename(ctx context.Context, databaseURL string, filenamePatter // strip suffixes that may be nested, such as .tar.gz basename := strings.SplitN(filename, ".", 2)[0] // get date version from basename - date := strings.SplitN(basename, "_", 2)[1] + parts := strings.SplitN(basename, "_", 2) + if len(parts) < 2 || parts[1] == "" { + return "", fmt.Errorf("unexpected database filename %q: missing date suffix", filename) + } + date := parts[1] // format db as "GeoLite2-Cities-{maxmind|geonames}_{DATE}.{mmdb|db}" databaseFilename := filepath.Base(strings.Replace(filenamePattern, "*", date, 1)) diff --git a/management/server/geolocation/utils.go b/management/server/geolocation/utils.go index 5104b0a08..0c4a66407 100644 --- a/management/server/geolocation/utils.go +++ b/management/server/geolocation/utils.go @@ -184,7 +184,12 @@ func getFilenameFromURL(url string) (string, error) { defer resp.Body.Close() - _, params, err := mime.ParseMediaType(resp.Header["Content-Disposition"][0]) + contentDisposition := resp.Header.Get("Content-Disposition") + if contentDisposition == "" { + return "", fmt.Errorf("no Content-Disposition header in response from %s", url) + } + + _, params, err := mime.ParseMediaType(contentDisposition) if err != nil { return "", err }