VYPR
High severityNVD Advisory· Published Mar 20, 2026· Updated Mar 21, 2026

free5GC NRF Discovery EncodeGroupId Function Panics on Malformed group-id-list Parameter

CVE-2026-33062

Description

free5GC is an open source 5G core network. free5GC NRF prior to version 1.4.2 has an Improper Input Validation vulnerability leading to Denial of Service. All deployments of free5GC using the NRF discovery service are affected. The EncodeGroupId function attempts to access array indices [0], [1], [2] without validating the length of the split data. When the parameter contains insufficient separator characters, the code panics with "index out of range". A remote attacker can cause the NRF service to panic and crash by sending a crafted HTTP GET request with a malformed group-id-list parameter. This results in complete denial of service for the NRF discovery service. free5GC NRF version 1.4.2 fixes the issue. There is no direct workaround at the application level. The recommendation is to apply the provided patch or restrict access to the NRF API to trusted sources only.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
github.com/free5gc/nrfGo
< 1.4.21.4.2

Affected products

1

Patches

1
dac77d8f8f2e

Merge pull request #80 from Zach1113/fix/nf-discovery-parameter-validation

https://github.com/free5gc/nrfFeng TuFeb 5, 2026via ghsa
3 files changed · +76 54
  • go.mod+1 1 modified
    @@ -5,7 +5,7 @@ go 1.25.5
     require (
     	github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d
     	github.com/free5gc/openapi v1.2.3
    -	github.com/free5gc/util v1.3.2-0.20260107090449-c09baaf75b11
    +	github.com/free5gc/util v1.3.2-0.20260204030658-79d56f347175
     	github.com/gin-gonic/gin v1.10.0
     	github.com/golang-jwt/jwt/v5 v5.2.2
     	github.com/google/uuid v1.6.0
    
  • go.sum+4 2 modified
    @@ -29,8 +29,8 @@ github.com/free5gc/ngap v1.1.2 h1:AA+s9+eaE8fSTnmBbh1xiD3VPaszonCd7AQJGKX5PHM=
     github.com/free5gc/ngap v1.1.2/go.mod h1:4HYtB+msoTBc3cEPlSr4ZUUHn3BFZhdPuVASERMzVeI=
     github.com/free5gc/openapi v1.2.3 h1:w4TmYBR8TUE4ZgKo7eiMZbyZPURSBFlMWiFeX+OsiA8=
     github.com/free5gc/openapi v1.2.3/go.mod h1:fLvaBtUZrvrzkKrmn5Aza+JNbpWnp3kxKixu6kLSD3k=
    -github.com/free5gc/util v1.3.2-0.20260107090449-c09baaf75b11 h1:/UZetXmPa5T/TKKxqU3Osw9x3+nIuACTXJxOU+gYGTU=
    -github.com/free5gc/util v1.3.2-0.20260107090449-c09baaf75b11/go.mod h1:qsv/ez8YhI+pO8bjNiZWXc2xmRE3XuEIa0EDTCPkSy0=
    +github.com/free5gc/util v1.3.2-0.20260204030658-79d56f347175 h1:F1KLSNuHBQzQC2rjC0Zu0ehaAc1n2Gmkw52g8YgnsdY=
    +github.com/free5gc/util v1.3.2-0.20260204030658-79d56f347175/go.mod h1:qsv/ez8YhI+pO8bjNiZWXc2xmRE3XuEIa0EDTCPkSy0=
     github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
     github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
     github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
    @@ -59,6 +59,8 @@ github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEW
     github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
     github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
     github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
    +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
    +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
     github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
     github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
     github.com/gopherjs/gopherjs v1.17.2 h1:fQnZVsXk8uxXIStYb0N4bGk7jeyTalG/wsZjQ25dO0g=
    
  • internal/sbi/processor/nf_discovery.go+71 51 modified
    @@ -2,6 +2,7 @@ package processor
     
     import (
     	"encoding/json"
    +	"fmt"
     	"log"
     	"math/big"
     	"net/http"
    @@ -123,10 +124,18 @@ func (p *Processor) NFDiscoveryProcedure(c *gin.Context, queryParameters url.Val
     		}
     	}
     
    -	// Check ComplexQuery (FOR REPORT PROBLEM!)
    -
     	// Build Query Filter
    -	filter := buildFilter(queryParameters)
    +	filter, err := buildFilter(queryParameters)
    +	if err != nil {
    +		problemDetails := &models.ProblemDetails{
    +			Title:  "Invalid Parameter",
    +			Status: http.StatusBadRequest,
    +			Cause:  "INVALID_QUERY_PARAM",
    +			Detail: err.Error(),
    +		}
    +		util.GinProblemJson(c, problemDetails)
    +		return
    +	}
     	logger.DiscLog.Traceln("Query filter: ", filter)
     
     	// Use the filter to find documents
    @@ -198,7 +207,7 @@ func (p *Processor) NFDiscoveryProcedure(c *gin.Context, queryParameters url.Val
     	c.JSON(http.StatusOK, searchResult)
     }
     
    -func buildFilter(queryParameters url.Values) bson.M {
    +func buildFilter(queryParameters url.Values) (bson.M, error) {
     	// build the filter
     	filter := bson.M{
     		"$and": []bson.M{},
    @@ -392,8 +401,8 @@ func buildFilter(queryParameters url.Values) bson.M {
     
     	// [Query-12] dnn
     	if queryParameters["dnn"] != nil {
    -		dnn := queryParameters["dnn"][0]
     		var dnnFilter bson.M
    +		dnn := queryParameters["dnn"][0]
     		switch targetNfType {
     		case "SMF":
     			dnnFilter = bson.M{
    @@ -446,15 +455,16 @@ func buildFilter(queryParameters url.Values) bson.M {
     				},
     			}
     		}
    -		filter["$and"] = append(filter["$and"].([]bson.M), dnnFilter)
    +		if dnnFilter != nil {
    +			filter["$and"] = append(filter["$and"].([]bson.M), dnnFilter)
    +		}
     	}
     
     	// [Query-13] smf-serving-area
     	if queryParameters["smf-serving-area"] != nil {
    -		var smfServingAreaFilter bson.M
     		smfServingArea := queryParameters["smf-serving-area"][0]
     		if targetNfType == "UPF" {
    -			smfServingAreaFilter = bson.M{
    +			filter["$and"] = append(filter["$and"].([]bson.M), bson.M{
     				"$or": []bson.M{
     					{
     						"upfInfo.smfServingArea": smfServingArea,
    @@ -465,9 +475,8 @@ func buildFilter(queryParameters url.Values) bson.M {
     						},
     					},
     				},
    -			}
    +			})
     		}
    -		filter["$and"] = append(filter["$and"].([]bson.M), smfServingAreaFilter)
     	}
     
     	// [Query-14] tai
    @@ -505,7 +514,9 @@ func buildFilter(queryParameters url.Values) bson.M {
     				},
     			}
     		}
    -		filter["$and"] = append(filter["$and"].([]bson.M), taiFilter)
    +		if taiFilter != nil {
    +			filter["$and"] = append(filter["$and"].([]bson.M), taiFilter)
    +		}
     	}
     
     	// [Query-15] amf-region-id
    @@ -697,16 +708,17 @@ func buildFilter(queryParameters url.Values) bson.M {
     				},
     			}
     		}
    -		filter["$and"] = append(filter["$and"].([]bson.M), supiFilter)
    +		if supiFilter != nil {
    +			filter["$and"] = append(filter["$and"].([]bson.M), supiFilter)
    +		}
     	}
     
     	// [Query-19] ue-ipv4-address
     	if queryParameters["ue-ipv4-address"] != nil {
    -		var ueIpv4AddressFilter bson.M
     		if targetNfType == "BSF" {
     			ueIpv4Address := queryParameters["ue-ipv4-address"][0]
     			ueIpv4AddressNumber := nrf_context.Ipv4ToInt(ueIpv4Address)
    -			ueIpv4AddressFilter = bson.M{
    +			filter["$and"] = append(filter["$and"].([]bson.M), bson.M{
     				"$or": []bson.M{
     					{
     						"bsfInfo.ipv4AddressRanges": bson.M{
    @@ -726,17 +738,15 @@ func buildFilter(queryParameters url.Values) bson.M {
     						},
     					},
     				},
    -			}
    +			})
     		}
    -		filter["$and"] = append(filter["$and"].([]bson.M), ueIpv4AddressFilter)
     	}
     
     	// [Query-20] ip-domain
     	if queryParameters["ip-domain"] != nil {
    -		var ipDomainFilter bson.M
     		if targetNfType == "BSF" {
     			ipDomain := queryParameters["ip-domain"][0]
    -			ipDomainFilter = bson.M{
    +			filter["$and"] = append(filter["$and"].([]bson.M), bson.M{
     				"$or": []bson.M{
     					{
     						"bsfInfo.ipDomainList": ipDomain,
    @@ -747,18 +757,16 @@ func buildFilter(queryParameters url.Values) bson.M {
     						},
     					},
     				},
    -			}
    +			})
     		}
    -		filter["$and"] = append(filter["$and"].([]bson.M), ipDomainFilter)
     	}
     
     	// [Query-21] ue-ipv6-prefix
     	if queryParameters["ue-ipv6-prefix"] != nil {
    -		var ueIpv6PrefixFilter bson.M
     		if targetNfType == "BSF" {
     			ueIpv6Prefix := queryParameters["ue-ipv6-prefix"][0]
     			ueIpv6PrefixNumber := nrf_context.Ipv6ToInt(ueIpv6Prefix)
    -			ueIpv6PrefixFilter = bson.M{
    +			filter["$and"] = append(filter["$and"].([]bson.M), bson.M{
     				"$or": []bson.M{
     					{
     						"bsfInfo.ipv6PrefixRanges": bson.M{
    @@ -778,9 +786,8 @@ func buildFilter(queryParameters url.Values) bson.M {
     						},
     					},
     				},
    -			}
    +			})
     		}
    -		filter["$and"] = append(filter["$and"].([]bson.M), ueIpv6PrefixFilter)
     	}
     
     	// [Query-22] pgw-ind
    @@ -894,14 +901,20 @@ func buildFilter(queryParameters url.Values) bson.M {
     				},
     			}
     		}
    -		filter["$and"] = append(filter["$and"].([]bson.M), gpsiFilter)
    +		if gpsiFilter != nil {
    +			filter["$and"] = append(filter["$and"].([]bson.M), gpsiFilter)
    +		}
     	}
     
     	// [Query-25] external-group-identity
     	if queryParameters["external-group-identity"] != nil {
     		var externalGroupIdentityFilter bson.M
     		externalGroupIdentity := queryParameters["external-group-identity"][0]
     
    +		if err := validator.ValidateGroupIdFormat(externalGroupIdentity); err != nil {
    +			return nil, fmt.Errorf("invalid external-group-identity: %w", err)
    +		}
    +
     		encodedGroupId := nrf_context.EncodeGroupId(externalGroupIdentity)
     
     		switch targetNfType {
    @@ -966,15 +979,16 @@ func buildFilter(queryParameters url.Values) bson.M {
     				},
     			}
     		}
    -		filter["$and"] = append(filter["$and"].([]bson.M), externalGroupIdentityFilter)
    +		if externalGroupIdentityFilter != nil {
    +			filter["$and"] = append(filter["$and"].([]bson.M), externalGroupIdentityFilter)
    +		}
     	}
     
     	// [Query-26] data-set
     	if queryParameters["data-set"] != nil {
    -		var dataSetFilter bson.M
     		dataSet := queryParameters["data-set"]
     		if targetNfType == "UDR" {
    -			dataSetFilter = bson.M{
    +			filter["$and"] = append(filter["$and"].([]bson.M), bson.M{
     				"$or": []bson.M{
     					{
     						"udrInfo.supportedDataSets": dataSet,
    @@ -985,9 +999,8 @@ func buildFilter(queryParameters url.Values) bson.M {
     						},
     					},
     				},
    -			}
    +			})
     		}
    -		filter["$and"] = append(filter["$and"].([]bson.M), dataSetFilter)
     	}
     
     	// [Query-27] routing-indicator
    @@ -1022,7 +1035,9 @@ func buildFilter(queryParameters url.Values) bson.M {
     				},
     			}
     		}
    -		filter["$and"] = append(filter["$and"].([]bson.M), routingIndicatorFilter)
    +		if routingIndicatorFilter != nil {
    +			filter["$and"] = append(filter["$and"].([]bson.M), routingIndicatorFilter)
    +		}
     	}
     
     	// [Query-28] group-id-list
    @@ -1057,12 +1072,13 @@ func buildFilter(queryParameters url.Values) bson.M {
     				},
     			}
     		}
    -		filter["$and"] = append(filter["$and"].([]bson.M), groupIdListFilter)
    +		if groupIdListFilter != nil {
    +			filter["$and"] = append(filter["$and"].([]bson.M), groupIdListFilter)
    +		}
     	}
     
     	// [Query-29] dnai-list
     	if queryParameters["dnai-list"] != nil {
    -		var dnaiFilter bson.M
     		dnaiList := queryParameters["dnai-list"][0]
     		dnaiListSplit := strings.Split(dnaiList, ",")
     		var dnaiListBsonArray bson.A
    @@ -1071,7 +1087,7 @@ func buildFilter(queryParameters url.Values) bson.M {
     			dnaiListBsonArray = append(dnaiListBsonArray, v)
     		}
     		if targetNfType == "UPF" {
    -			dnaiFilter = bson.M{
    +			filter["$and"] = append(filter["$and"].([]bson.M), bson.M{
     				"upfInfo.sNssaiUpfInfoList": bson.M{
     					"$elemMatch": bson.M{
     						"dnnUpfInfoList": bson.M{
    @@ -1083,26 +1099,22 @@ func buildFilter(queryParameters url.Values) bson.M {
     						},
     					},
     				},
    -			}
    +			})
     		}
    -		filter["$and"] = append(filter["$and"].([]bson.M), dnaiFilter)
     	}
     
     	// [Query-30] upf-iwk-eps-ind
     	if queryParameters["upf-iwk-eps-ind"] != nil {
    -		var upfIwkEpsIndFilter bson.M
     		// upfIwkEpsInd := queryParameters["upf-iwk-eps-ind"][0]
     		if targetNfType == "UPF" {
    -			upfIwkEpsIndFilter = bson.M{
    +			filter["$and"] = append(filter["$and"].([]bson.M), bson.M{
     				"upfInfo.iwkEpsInd": true,
    -			}
    +			})
     		}
    -		filter["$and"] = append(filter["$and"].([]bson.M), upfIwkEpsIndFilter)
     	}
     
     	// [Query-31] chf-supported-plmn
     	if queryParameters["chf-supported-plmn"] != nil {
    -		var chfSupportedPlmnFilter bson.M
     		chfSupportedPlmn := queryParameters["chf-supported-plmn"][0]
     		chfSupportedPlmnStruct := &models.PlmnId{}
     		err := json.Unmarshal([]byte(chfSupportedPlmn), chfSupportedPlmnStruct)
    @@ -1113,7 +1125,7 @@ func buildFilter(queryParameters url.Values) bson.M {
     		encodedchfSupportedPlmn := chfSupportedPlmnStruct.Mcc + chfSupportedPlmnStruct.Mnc
     
     		if targetNfType == "CHF" {
    -			chfSupportedPlmnFilter = bson.M{
    +			filter["$and"] = append(filter["$and"].([]bson.M), bson.M{
     				"$or": []bson.M{
     					{
     						"chfInfo.plmnRangeList": bson.M{
    @@ -1133,9 +1145,8 @@ func buildFilter(queryParameters url.Values) bson.M {
     						},
     					},
     				},
    -			}
    +			})
     		}
    -		filter["$and"] = append(filter["$and"].([]bson.M), chfSupportedPlmnFilter)
     	}
     
     	// [Query-32]  preferred-locality
    @@ -1188,10 +1199,13 @@ func buildFilter(queryParameters url.Values) bson.M {
     		if err != nil {
     			logger.DiscLog.Warnln("Unmarshal Error in complexQuery: ", err)
     		}
    -		complexQueryFilter := complexQueryFilter(complexQueryStruct)
    +		complexQueryFilter, err := complexQueryFilter(complexQueryStruct)
    +		if err != nil {
    +			return nil, err
    +		}
     		filter["$and"] = append(filter["$and"].([]bson.M), complexQueryFilter)
     	}
    -	return filter
    +	return filter, nil
     }
     
     const (
    @@ -1204,7 +1218,7 @@ type AtomElem struct {
     	negative bool
     }
     
    -func complexQueryFilter(complexQueryParameter *models.ComplexQuery) bson.M {
    +func complexQueryFilter(complexQueryParameter *models.ComplexQuery) (bson.M, error) {
     	complexQueryType := ""
     	if complexQueryParameter.CnfUnits != nil {
     		complexQueryType = COMPLEX_QUERY_TYPE_CNF
    @@ -1230,7 +1244,10 @@ func complexQueryFilter(complexQueryParameter *models.ComplexQuery) bson.M {
     				value := string(valueJson)
     				queryParameters[atom.Attr] = &AtomElem{value: value, negative: atom.Negative}
     			}
    -			cnfUnitFilter = complexQueryFilterSubprocess(queryParameters, complexQueryType)
    +			cnfUnitFilter, err := complexQueryFilterSubprocess(queryParameters, complexQueryType)
    +			if err != nil {
    +				return nil, err
    +			}
     
     			filter["$and"] = append(filter["$and"].([]bson.M), cnfUnitFilter)
     		}
    @@ -1239,10 +1256,10 @@ func complexQueryFilter(complexQueryParameter *models.ComplexQuery) bson.M {
     			"$or": []bson.M{},
     		}
     	}
    -	return filter
    +	return filter, nil
     }
     
    -func complexQueryFilterSubprocess(queryParameters map[string]*AtomElem, complexQueryType string) bson.M {
    +func complexQueryFilterSubprocess(queryParameters map[string]*AtomElem, complexQueryType string) (bson.M, error) {
     	var filter bson.M
     	var logicalOperator string
     
    @@ -1576,6 +1593,9 @@ func complexQueryFilterSubprocess(queryParameters map[string]*AtomElem, complexQ
     		var taiFilter bson.M
     		tai := queryParameters["tai"].value
     		taiSplit := strings.Split(tai, ",")
    +		if len(taiSplit) < 2 {
    +			return nil, fmt.Errorf("invalid tai format: insufficient comma-separated values")
    +		}
     		tempTai := taiSplit[0] + "," + taiSplit[1]
     
     		taiStruct := &models.Tai{}
    @@ -2274,5 +2294,5 @@ func complexQueryFilterSubprocess(queryParameters map[string]*AtomElem, complexQ
     		filter[logicalOperator] = append(filter[logicalOperator].([]bson.M), supportedFeaturesFilter)
     	}
     
    -	return filter
    +	return filter, nil
     }
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

6

News mentions

0

No linked articles in our index yet.