GitHub Security Advisory: GHSA-f8qv-7x5w-qr48
Package: github.com/free5gc/nrf (GO)
Severity: HIGH (CVSS 7.5)
CWE: CWE-20: Improper Input Validation, CWE-755: Improper Handling of Exceptional Conditions, CWE-843: Access of Resource Using Incompatible Type ('Type Confusion')
Vulnerable versions: < 1.4.3
Patched in: 1.4.3

Summary: free5GC NRF: type-confusion panic in POST /oauth2/token structured-form parser via Reflect.Set on incompatible types

Details:
### Summary
free5GC's NRF root SBI endpoint `POST /oauth2/token` contains a parser-level type-confusion bug family. The handler in `NFs/nrf/internal/sbi/api_accesstoken.go` reflects over `models.NrfAccessTokenAccessTokenReq`, special-cases only plain `string` and `NrfNfManagementNfType` fields, and treats every other field as if it were a single `models.PlmnId`. The parsed `*models.PlmnId` is then assigned with `reflect.Value.Set()` to whichever field name the attacker put in the form body, which panics whenever the destination field's real type is incompatible (slice, different struct, primitive). Gin recovery converts each panic into `HTTP 500`, but the endpoint remains remotely panicable from a single unauthenticated form-encoded request and is repeatedly triggerable across at least 6 confirmed crashing fields.

Note: `/oauth2/token` is unauthenticated by design (it is the OAuth2 token-issuance endpoint). So this is NOT framed as an auth-bypass finding -- it is a parser bug on an intentionally unauthenticated SBI endpoint.

### Details
Validated against the NRF container in the official Docker compose lab.
- Source repo tag: `v4.2.1`
- Running Docker image: `free5gc/nrf:v4.2.1`
- Docker validation date: 2026-03-22
- NRF endpoint: `http://10.100.200.3:8000`

Root cause is in the access-token request parser:
- `NFs/nrf/internal/sbi/api_accesstoken.go:52`
- `NFs/nrf/internal/sbi/api_accesstoken.go:87`
- `NFs/nrf/internal/sbi/api_accesstoken.go:98`
- `NFs/nrf/internal/sbi/api_accesstoken.go:100`
- `NFs/nrf/internal/sbi/api_accesstoken.go:112`

The model definition lives in `free5gc/openapi`:
- `models/model_nrf_access_token_access_token_req.go:27`
- `models/model_nrf_access_token_access_token_req.go:29`
- `models/model_nrf_access_token_access_token_req.go:30`
- `models/model_nrf_access_token_access_token_req.go:31`

The parser's effective shape is: parse value as `*models.PlmnId`, then `dstField.Set(reflect.ValueOf(parsedPlmnId))`. Every destination field that is NOT `string` and NOT `NrfNfManagementNfType` falls into this branch, so any time the destination is a slice (`[]models.PlmnId`, `[]models.Snssai`, `[]models.PlmnIdNid`, `[]string`) or a different pointer type (`*models.PlmnIdNid`), the `reflect.Set` call panics with a runtime type-confusion error.

Confirmed crashing fields in this DoS family (all reachable from a single unauthenticated form-encoded POST):
- `requesterPlmnList` -> panic assigning `*models.PlmnId` to `[]models.PlmnId`
- `requesterSnssaiList` -> panic assigning `*models.PlmnId` to `[]models.Snssai`
- `requesterSnpnList` -> panic assigning `*models.PlmnId` to `[]models.PlmnIdNid`
- `targetSnpn` -> panic assigning `*models.PlmnId` to `*models.PlmnIdNid`
- `targetSnssaiList` -> panic assigning `*models.PlmnId` to `[]models.Snssai`
- `targetNsiList` -> panic assigning `*models.PlmnId` to `[]string`

### PoC
Reproduced end-to-end against the running NRF at `http://10.100.200.3:8000`. Each of the following single requests indepen