Jun 8, 2026·7 min read·20 visits
Authenticated attackers can exploit a Server-Side Request Forgery (SSRF) flaw in GeoNode's service registration workflow to probe internal networks, port scan local services, and query cloud metadata endpoints by supplying crafted service URLs.
GeoNode versions prior to 4.4.5 and 5.0.2 are vulnerable to Server-Side Request Forgery (SSRF) in the service registration endpoint. Authenticated attackers with low privileges can exploit insufficient input validation in the Web Map Service (WMS) registration module to force the application server to make outbound network queries to loopback addresses, private RFC1918 subnets, link-local scopes, and cloud metadata endpoints. This technical report details the mechanics of the vulnerability, the underlying architectural flaw, and how to effectively remediate and mitigate the associated security risks.
GeoNode is an open-source web-based geographic information system (GIS) platform that enables administrative and low-privilege users to share, manage, and edit geospatial datasets. The application utilizes the Django framework and integrates with backend geospatial servers such as GeoServer to render maps and manage spatial layers. To expand its repository, GeoNode permits users to link external Open Geospatial Consortium (OGC) web services, such as Web Map Services (WMS), to pull remote spatial data directly into the local workspace.
This integration capability introduces a requirement to programmatically verify remote services prior to persistent registration. During registration, the GeoNode backend initiates an HTTP connection to the remote server to fetch capabilities metadata and confirm the remote service is active. This process runs within the application security context, inheriting the network capabilities and access privileges of the hosting server environment.
The service registration form validation routine exposes an attack surface that allows input URLs to be processed without validation of the destination host. Because low-privileged users are authorized to register services, an authenticated attacker can access the registration form to input arbitrary URLs. The application fails to restrict target hosts, allowing attackers to route arbitrary HTTP queries to internal networks and local server resources.
The vulnerability belongs to the Server-Side Request Forgery (SSRF) class, cataloged as CWE-918. The underlying security defect lies within the service handler responsible for validating WMS URLs during form submission. When a user submits a WMS registration request, the backend initiates a validation loop to verify the URL's schema and retrieve the remote capabilities document.
To perform this verification, the backend parses the user-provided string and initializes an HTTP request without resolving the target domain beforehand to inspect the destination IP address. Because there is no check to ensure the resolved IP address is a public, routable destination, the server attempts to establish TCP socket connections to loopback networks, local private subnets, and link-local ranges.
Furthermore, the application does not implement a domain allowlist or IP blocklist. This oversight allows attackers to specify local endpoints, private RFC1918 addresses, and sensitive cloud API endpoints such as the standard cloud metadata server at 169.254.169.254. Since the backend processes these requests under the server process context, any firewall boundaries protecting the internal network from external access are bypassed.
In vulnerable versions of GeoNode, the service validation logic evaluates whether the target URL belongs to a valid Web Map Service. The logic accepts the base URL directly from the user form data and initiates an outbound network connection using internal libraries. The code snippet below demonstrates how the insecure implementation processes user-supplied URLs without restricting the destination host.
# Insecure WMS registration validation
import requests
from django.core.exceptions import ValidationError
from owslib.wms import WebMapService
def validate_remote_wms(base_url):
# INSECURE: No resolution checks are performed on the host.
# Any loopback, private RFC1918, or metadata IP will be requested.
try:
wms = WebMapService(base_url, timeout=5)
return True
except Exception as e:
raise ValidationError(f"Could not connect to service: {e}")The remediation strategy introduces a dedicated validation layer that intercepts the input URL before any network socket is opened. It resolves the hostname and evaluates all returned IP addresses against a designated blocklist of private, local, and reserved network ranges. The following block demonstrates the secure validation structure implemented in the updated versions.
# Patched and secure service validation implementation
import socket
import ipaddress
from urllib.parse import urlparse
from django.core.exceptions import ValidationError
def is_safe_destination(url):
try:
parsed_url = urlparse(url)
hostname = parsed_url.hostname
if not hostname:
return False
# Resolve hostname to all associated IP addresses to prevent DNS pinning bypasses
addr_info = socket.getaddrinfo(hostname, None)
for family, _, _, _, sockaddr in addr_info:
ip_str = sockaddr[0]
ip = ipaddress.ip_address(ip_str)
# Block private, loopback, link-local, and multicast addresses
if ip.is_private or ip.is_loopback or ip.is_link_local or ip.is_multicast:
return False
return True
except Exception:
return False
def validate_remote_wms_secure(base_url):
# SECURE: Validate destination before initiating any external connection
if not is_safe_destination(base_url):
raise ValidationError("Insecure URL destination: Access to internal IP ranges is prohibited.")
# Safe to perform outbound verification
from owslib.wms import WebMapService
wms = WebMapService(base_url, timeout=5)
return TrueThis implementation mitigates DNS rebinding bypass attempts by validating every IP address resolved during DNS queries. Even if an attacker uses a domain that dynamically alternates between public and private IP addresses, the custom validation layer blocks the execution because all resolved IP addresses must pass the safety checks.
To exploit this vulnerability, an attacker must first obtain standard authenticated credentials on the target GeoNode instance. Once authenticated, the attacker accesses the service registration module via the user interface or by sending a direct POST request to the services API endpoint. The attacker submits a registration payload with the base URL configured to target internal systems instead of a legitimate public WMS endpoint.
An attacker can perform internal port scanning by submitting URLs targeting specific ports on loopback or private hosts. For example, submitting http://127.0.0.1:5432 targets an internal PostgreSQL database, while http://127.0.0.1:6379 targets a Redis instance. By monitoring the response times and error messages returned by the GeoNode backend, the attacker can infer the operational status of internal ports.
POST /api/v2/services/ HTTP/1.1
Host: geonode.example.com
Authorization: Bearer <valid_user_token>
Content-Type: application/json
{
"base_url": "http://169.254.169.254/latest/meta-data/",
"service_type": "WMS",
"name": "metadata_probe_service"
}In cloud environments, this methodology is utilized to query the instance metadata service to extract administrative credentials. For instance, querying the AWS link-local IP retrieves the IAM role security credentials associated with the host server. The returned response or error trace can leak these secrets back to the attacker, leading to broader compromise of the cloud infrastructure.
The CVSS v3.1 base score is assessed at 6.3, reflecting a Medium severity profile. The score is constrained because exploiting the flaw requires authenticating with at least low-privileged credentials, and the impact does not directly grant arbitrary code execution. However, the vector string CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:L highlights partial compromises in confidentiality, integrity, and availability.
The primary risk associated with this SSRF vulnerability is the exposure of internal-only infrastructure components. Many internal services, such as databases, microservices, and monitoring systems, operate with reduced authentication checks under the assumption that they are isolated from public ingress. Using GeoNode as an exploitation proxy allows attackers to bypass boundary network controls to execute arbitrary commands or modify data configurations on these unprotected internal servers.
The vulnerability also presents a risk of cloud infrastructure exposure through the leakage of instance metadata. Extracting temporary security tokens from the metadata endpoint enables lateral movement inside the associated cloud environment. While the current EPSS score is 0.00044, indicating low active exploitation probability, the potential impact warrants immediate patching to secure deployment boundaries.
Remediation of CVE-2026-39922 requires updating the GeoNode installation to a non-vulnerable release. For deployments operating on the 4.x release line, administrators must upgrade to version 4.4.5 or higher. For deployments running on the 5.x release line, upgrading to version 5.0.2 or higher is necessary to secure the service registration endpoints.
If an immediate upgrade is not feasible, network-level egress filtering must be configured on the host or container runtime. Egress security rules should be configured to prevent the GeoNode application server from sending packets to private subnets or localhost interfaces. In containerized environments, this can be enforced using network policies or iptables configurations that drop outbound traffic directed to the 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, and 169.254.169.254 scopes.
For cloud deployments, IMDSv2 must be mandated with a hop limit set to 1. This prevents the containerized GeoNode application from receiving responses from the metadata endpoint because the IP packet TTL is decremented below the threshold required to return to the container namespace. Additionally, administrators should review Django authentication configurations to limit the permission to register remote services to highly trusted users.
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:L| Product | Affected Versions | Fixed Version |
|---|---|---|
GeoNode GeoNode | >= 4.0.0, < 4.4.5 | 4.4.5 |
GeoNode GeoNode | >= 5.0.0, < 5.0.2 | 5.0.2 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-918 (Server-Side Request Forgery) |
| Attack Vector | Network (AV:N) |
| CVSS v3.1 Base Score | 6.3 (Medium) |
| EPSS Score | 0.00044 |
| Impact | Internal Port Scanning, Cloud Metadata Extraction, and Subnet Reconnaissance |
| Exploit Status | Proof of Concept (PoC) documented |
| KEV Status | Not Listed |
The web application receives a URL from an upstream component and executes an HTTP query without validating that the destination lies on a public, non-reserved IP subnet, allowing attackers to access internal network resources.
An improper access control vulnerability in JupyterLab allows programmatic installation of blocked or non-allowed extensions. The vulnerability is caused by a missing await keyword when invoking the asynchronous checking method, leading Python to evaluate the returned coroutine object as truthy. Furthermore, the check lacks proper canonicalization of package names, enabling an attacker to bypass blocklists using casing or character variants.
An unsigned 32-bit integer underflow vulnerability in the Windows Management Instrumentation (WMI) serialization subsystem of ntoskrnl.exe allows local authenticated users with low privileges to corrupt adjacent kernel pool allocations, execute arbitrary kernel-mode read and write operations, and perform a Token Swap attack to escalate their privileges to NT AUTHORITY\SYSTEM.
JupyterLab's PluginManager contains an authorization bypass vulnerability allowing authenticated users to modify the state of locked extensions or plugins. Although the frontend user interface visually locks and disables toggle components for administrative configurations, the backend API fails to perform robust validation. Standard users can craft direct HTTP API requests to modify plugin states, completely bypassing administrative restrictions.
GHSA-89VP-JRXV-24W8 is a security bypass vulnerability in the JupyterLab Extension Manager. Authenticated users can install unauthorized or blocklisted extension packages from PyPI. This bypass occurs due to improper canonicalization of package names and the incorrect synchronous invocation of an asynchronous permission-checking method.
A stored Cross-Site Scripting (XSS) vulnerability exists in JupyterLab's Image Viewer component when processing Scalable Vector Graphics (SVG) images. Due to the lingering lifecycle of generated object URLs and the inheritance of the application origin by client-side Blobs, an attacker can execute arbitrary JavaScript within the victim's active session. This execution occurs when a user views an SVG file in the JupyterLab image viewer, right-clicks the image, and selects 'Open image in new tab'.
JupyterLab versions 4.5.x and 4.6.x prior to 4.5.10 and 4.6.2 are vulnerable to a DOM-based Cross-Site Scripting (XSS) vulnerability. An attacker can craft a malicious overrides.json file that executes arbitrary JavaScript inside the victim's browser session. This can occur either automatically if the file is pre-planted on a multi-tenant filesystem, or via user interaction when importing settings.