GHSA-jqfc-gwj5-3w63: free5GC's UDR nudr-dr DELETE amf-subscriptions panics on missing UE state via nil interface type assertion (single authenticated request)
Summaryfree5GC's UDR `nudr-dr` `DELETE /subscription-data/{ueId}/{servingPlmnId}/ee-subscriptions/{subsId}/amf-subscriptions` handler panics on a single authenticated request against a fresh UDR instance when the supplied `ueId` does not exist in `UESubsCollection`. The processor checks `value, ok := udrSelf.UESubsCollection.Load(ueId)` and sets a `404 USER_NOT_FOUND` problem-details on the miss path, but execution continues and immediately runs `value.(*udr_context.UESubsData)` -- a Go type assertion on a nil interface, which panics with `interface conversion: interface {} is nil, not *context.UESubsData`. Gin recovery converts the panic into `HTTP 500`, but the endpoint remains repeatedly panicable.This is the no-precondition sibling of free5gc/free5gc#919: same handler, same bug pattern (set `pd`, do not return, then dereference), but the panic site is the nil-interface type assertion at line 61 instead of the nil-pointer deref at line 69. No earlier EE-subscription create is required.This endpoint requires a valid `nudr-dr` OAuth2 access token (PR:L, NOT PR:N), so this is scored as an authenticated panic-DoS, not as an unauth-bypass finding.DetailsValidated against the UDR container in the official Docker compose lab.Source repo tag: `v4.2.1`Running Docker image: `free5gc/udr:v4.2.1`Runtime UDR commit: `754d23b0`Docker validation date: 2026-03-22UDR endpoint: `http://10.100.200.11:8000`Vulnerable handler (the `ok` miss path sets `pd` but does not return; the next line type-asserts the nil interface):In the processor:When `ueId` is absent from `UESubsCollection`, `value` is the nil `interface{}` returned by `sync.Map.Load`, and `value.(*udr_context.UESubsData)` panics with:Code evidence (paths in `free5gc/udr`):Route exposure + handler dispatch:`NFs/udr/internal/sbi/api_datarepository.go:2161``NFs/udr/internal/sbi/api_datarepository.go:2170``NFs/udr/internal/sbi/api_datarepository.go:2172`Panic root cause (nil interface type assertion):`NFs/udr/internal/sbi/processor/event_amf_subscription_info_document.go:53``NFs/udr/internal/sbi/processor/event_amf_subscription_info_document.go:56``NFs/udr/internal/sbi/processor/event_amf_subscription_info_document.go:61`PoCReproduced end-to-end against the running UDR at `http://10.100.200.11:8000` -- single authenticated request, no preconditions.Restart UDR (clean state -- proves no precondition is needed):Obtain a valid `nudr-dr` token from NRF:Trigger the panic with one DELETE for a nonexistent `ueId=x`:UDR container logs (`docker logs udr`) confirm the nil-interface conversion panic at `event_amf_subscription_info_document.go:61` inside `RemoveAmfSubscriptionsInfoProcedure`:ImpactIncorrect type conversion on a nil interface (CWE-704) inside an authenticated UDR data-repository handler, caused by improper handling of the missing-ueId branch (CWE-754): the handler sets a `404` problem-details value but does not return, then runs a Go type assertion on the nil interface returned by `sync.Map.Load`.This is NOT framed as an auth-bypass finding: the endpoint requires a valid `nudr-dr` OAuth2 access token. A network attacker who already holds (or can obtain) a valid token can:Trigger a reliable, single-request panic on the `amf-subscriptions` delete route against a fresh UDR (no preparatory state needed -- this is strictly easier than free5gc/free5gc#919).Repeat the trigger to sustain a per-request panic-DoS on UDR's data-repository surface, with each panic costing more CPU + log writes than the intended `404 USER_NOT_FOUND` response would have.No Confidentiality impact (the response is `500` with empty body). No Integrity impact (the panic happens before any state mutation). Availability impact is limited to per-request degradation (Gin recovers; the UDR process keeps running).Affected: free5gc v4.2.1.Upstream issue: https://github.com/free5gc/free5gc/issues/920
Upstream fix: https://github.com/free5gc/udr/pull/60
CVSS v3.1: 6.5