Jul 14, 2026·4 min read·4 visits
A missing authorization check in Nebula-mesh allows non-admin operators to toggle the 'allow_private' parameter on webhooks, bypassing SSRF guards and allowing them to target internal systems.
Nebula-mesh allows non-admin operators to disable webhook SSRF (Server-Side Request Forgery) protection via the allow_private parameter. Low-privilege operators can configure webhook endpoints targeting internal endpoints and trigger lifecycle events on resources they own, bypassing network access controls.
In Nebula-mesh, non-admin operators (possessing the role user) can register and manage webhook subscriptions. The API exposes POST and PATCH endpoints at /api/v1/webhook-subscriptions to handle the webhook subscription lifecycle.
A severe authorization gap exists in this design. When creating or updating a webhook subscription, operators can set the parameter allow_private: true on their subscription requests. The backend fails to verify whether the operator has administrative privileges before persisting this parameter.
At the event delivery phase, when an event is fired, the event dispatcher checks the AllowPrivate field of the target subscription. If AllowPrivate is false, the dispatcher uses a guarded HTTP client that validates the destination URL and rejects loopback, private, and link-local addresses. If AllowPrivate is true, the dispatcher switches to an unguarded HTTP client, completely bypassing the Server-Side Request Forgery (SSRF) defenses.
The technical root cause of this vulnerability lies in the missing role-based access control (RBAC) within the webhook creation and modification controllers. In the file internal/api/webhooks.go, the handlers handleCreateWebhookSubscription and handleUpdateWebhookSubscription unpack client-provided payloads into internal model structs without filtering administrative toggles.
Specifically, the application defines a parameter named allow_private which allows requests to target loopback and RFC 1918 private subnets. Although the application contains a helper function s.isActiveAdmin(r.Context()) to enforce administrative restrictions on other handlers, this validation check was omitted from the webhook endpoints.
This structural oversight allows low-privilege operator sessions to successfully register endpoints matching loopback (127.0.0.1, localhost), private (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16), and link-local networks. The application then trustingly maps these configurations to an unguarded HTTP delivery engine during asynchronous event dispatch operations.
The vulnerability is resolved by explicitly introducing s.isActiveAdmin(r.Context()) verification before checking the validation rules of the incoming webhook configuration request.
Below is the code difference from the patched file internal/api/webhooks.go:
@@ -70,6 +70,10 @@ func (s *Server) handleCreateWebhookSubscription(w http.ResponseWriter, r *http.
writeError(w, http.StatusBadRequest, "invalid request body")
return
}
+ if req.AllowPrivate && !s.isActiveAdmin(r.Context()) {
+ writeError(w, http.StatusForbidden, "allow_private requires the admin role")
+ return
+ }
if err := config.ValidateWebhookURL("url", req.URL, req.AllowPrivate); err != nil {
writeError(w, http.StatusBadRequest, err.Error())
return
@@ -120,6 +124,10 @@ func (s *Server) handleUpdateWebhookSubscription(w http.ResponseWriter, r *http.
if req.URL == "" {
req.URL = sub.URL
}
+ if req.AllowPrivate && !s.isActiveAdmin(r.Context()) {
+ writeError(w, http.StatusForbidden, "allow_private requires the admin role")
+ return
+ }
if err := config.ValidateWebhookURL("url", req.URL, req.AllowPrivate); err != nil {
writeError(w, http.StatusBadRequest, err.Error())
returnWhile the patch successfully eliminates the direct authorization bypass on the allow_private parameter, organizations should evaluate remaining edge cases. The application relies on standard HTTP client resolution, which may be susceptible to DNS Rebinding variants if the destination hostname resolves to a public address during validation and a local address during socket connection.
Exploitation requires the attacker to possess an active session token with the base non-admin user role. Using this session, the attacker can configure and trigger the SSRF sequence.
To construct the bypass, the attacker submits a structured registration payload specifying allow_private set to true and pointing the delivery destination to an internal network target:
POST /api/v1/webhook-subscriptions HTTP/1.1
Host: 127.0.0.1:8181
Authorization: Bearer d984bbe6680a9b3f57def0caf8556466e502d35c8c287bd2f1fd6938fcda2e7c
Content-Type: application/json
{
"url": "http://127.0.0.1:9999/internal-admin",
"allow_private": true,
"events": ["host.enrolled"]
}Once registered, the attacker triggers an event associated with the subscription (e.g., enrolling or unblocking a host resource). The server processes the event, retrieves the subscription payload, and executes an asynchronous, blind POST request using its unguarded client. The attacker can subsequently poll the /api/v1/webhook-subscriptions/{id} endpoint to view the request dispatch status, using the returned error metrics as a rudimentary port scanner and reachability oracle.
The impact of this vulnerability is severe because it allows low-privilege actors to query restricted internal infrastructure directly from the host operating the Nebula-mesh service.
This network reachability bypasses firewalls and network segmentation rules. Attackers can interact with loopback management interfaces, probe ports on peer network hosts, or query Cloud Metadata Services (e.g., IMDSv1 at 169.254.169.254) to exfiltrate administrative IAM credentials.
Because the webhook dispatch mechanism processes responses and populates debugging information in the subscription metadata, the attacker gains a functional infrastructure scanning and enumeration vector. This allows them to systematically map internal services, potentially preparing for secondary exploits against vulnerable private APIs.
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
github.com/forgekeep/nebula-mesh forgekeep | >= 0.6.0, <= 0.7.1 | 0.7.2 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-862, CWE-918 |
| Attack Vector | Network |
| CVSS v3.1 Score | 7.7 |
| Exploit Status | poc |
| Impact | Server-Side Request Forgery (SSRF) |
The web application receives a user-supplied URL, passes it through, and makes a request to it on behalf of the attacker, bypassing security boundaries.
FacturaScripts is an open-source PHP-based enterprise resource planning (ERP) and billing software. A critical path traversal vulnerability in the file-handling logic allows authenticated attackers with file upload permissions to write arbitrary files to any location on the system writable by the web server user. By writing custom server configuration files (.htaccess) to directories excluded from default rewrite rules, attackers can map allowed file types (like .png) to the PHP interpreter, leading to full remote code execution.
An information exposure vulnerability exists in Umbraco.AI package versions up to 1.13.0, where an authenticated backoffice user with elevated privileges can resolve and retrieve arbitrary configuration values from the global ASP.NET Core IConfiguration hierarchy.
A technical analysis of CVE-2025-61670, a memory leak vulnerability in Wasmtime's C and C++ API bindings. The issue stems from a refactoring in version 37.0.0 that transitioned garbage-collected reference tracking to host heap-allocated OwnedRooted types without updating FFI ownership semantics.
A critical authentication bypass vulnerability in Woodpecker CI allows authenticated agents to impersonate other agents by injecting spoofed agent_id values into gRPC metadata. This flaw is caused by the use of md.Append instead of md.Set on the server-side RPC authorizer.
Fedify, a TypeScript framework for ActivityPub servers, implemented incomplete public URL validation inside the @fedify/fedify and @fedify/vocab-runtime libraries. The validator only blocked basic RFC 1918 networks, standard loopbacks, and link-local addresses, failing to restrict Carrier-Grade NAT (CGNAT), benchmarking, reserved, or IPv6 transition addresses. Consequently, unauthenticated remote attackers can bypass SSRF filters to access sensitive internal microservices and endpoints.
CVE-2026-54250 is a path traversal vulnerability in K3s, a lightweight Kubernetes distribution. The flaw exists within the etcd snapshot decompression functionality, allowing administrative users to write arbitrary files to the host filesystem via a maliciously crafted ZIP archive. Due to the high privilege level of the K3s process, this can result in total host compromise.