GitHub Security Advisory: GHSA-j59f-x285-69jx
Package: github.com/free5gc/nef (GO)
Severity: HIGH (CVSS 7.5)
CWE: CWE-476: NULL Pointer Dereference, CWE-754: Improper Check for Unusual or Exceptional Conditions
Vulnerable versions: < 1.2.3
Patched in: 1.2.3

Summary: free5GC's NEF 3gpp-pfd-management PATCH applications/{appId} panics on UDR access failure due to nil ProblemDetails dereference

Details:
### Summary
free5GC's NEF `PATCH /3gpp-pfd-management/v1/{afId}/transactions/{transId}/applications/{appId}` handler panics with a nil-pointer dereference when the upstream UDR call fails AND the consumer wrapper returns `err != nil` together with a nil `*ProblemDetails`. The handler's `errPfdData != nil` branch builds its own `problemDetailsErr` correctly, but immediately after it reads `problemDetails.Cause` (the OTHER value, which is nil in this branch) and panics. Gin recovery converts the panic into `HTTP 500`, so a single PATCH against this endpoint returns 500 instead of the intended controlled error response whenever UDR access is failing.

This is a second-order bug: the trigger requires UDR access to be failing (e.g. NRF or UDR is unreachable, registration broken, transient network failure). The attacker does not directly control that condition, so this is scored as AC:H. Once the upstream condition exists, the trigger is a single PATCH request and is repeatable.

The HTTP request itself in v4.2.1 is reachable without an `Authorization` header because the underlying NEF `3gpp-pfd-management` route group is mounted without inbound auth middleware (see free5gc/free5gc#858). So in the validation lab the entire trigger chain is unauthenticated end-to-end.

### Details
Validated against the NEF container in the official Docker compose lab.
- Source repo tag: `v4.2.1`
- Running Docker image: `free5gc/nef:v4.2.1`
- Runtime NEF commit: `5ce35eab`
- Docker validation date: 2026-03-21 (container log timestamp `2026-03-21T03:06:36Z`)
- NEF endpoint: `http://10.100.200.19:8000`

Vulnerable handler logic in `PatchIndividualApplicationPFDManagement` (paraphrased):
```go
pdfData, problemDetails, errPfdData := p.Consumer().AppDataPfdsAppIdGet(appID)

switch {
case problemDetails != nil:
    ...
case errPfdData != nil:
    problemDetailsErr := &models.ProblemDetails{
        Status: http.StatusInternalServerError,
        Detail: "Query to UDR failed",
    }
    c.Set(sbi.IN_PB_DETAILS_CTX_STR, problemDetails.Cause)   // <-- nil deref
    c.JSON(int(problemDetailsErr.Status), problemDetailsErr)
    return
}
```
In the `errPfdData != nil` branch, `problemDetails` is by construction nil (otherwise the first `case` would have matched). Reading `problemDetails.Cause` panics with `runtime error: invalid memory address or nil pointer dereference`. The intended value is presumably `problemDetailsErr.Cause` -- the locally constructed problem-details struct.

Code evidence (paths in `free5gc/nef`):
- Patch handler core path:
  - `NFs/nef/internal/sbi/processor/pfd.go:563`
  - `NFs/nef/internal/sbi/processor/pfd.go:610`
- Panic site (nil-deref on `problemDetails.Cause`):
  - `NFs/nef/internal/sbi/processor/pfd.go:622`
- Route exposure / dispatch:
  - `NFs/nef/internal/sbi/api_pfd.go:168`
  - `NFs/nef/internal/sbi/api_pfd.go:188`

### PoC
Reproduced end-to-end against the running NEF at `http://10.100.200.19:8000`. The trigger requires UDR access to be failing --