Jul 13, 2026·6 min read·5 visits
Unsanitized user-controlled metadata fields rendered via the safe filter in GeoNode templates allow unauthenticated or low-privilege users to store malicious script payloads. Upon administrative review, the script executes within the victim session, permitting silent account takeover.
A comprehensive security analysis of CVE-2024-27091, a stored cross-site scripting (XSS) vulnerability in the GeoNode geospatial content management system. Unsanitized metadata fields rendered with Django's safe template filter permit stored JavaScript execution, leading directly to admin account takeover via CSRF token theft and silent profile email modification.
GeoNode is a specialized geospatial content management system used globally to manage, catalog, and publish spatial databases. Because GeoNode hosts administrative functions and map publishing controls, its users often possess elevated system permissions. The application exposes an extensive metadata interface allowing users to document layers, maps, and documents. These metadata parameters accept rich-text formatting to facilitate highly structured documentation.
This documentation structure exposes a distinct attack surface. Unauthenticated or low-privilege registered users can submit custom metadata configurations via the platform's REST API or UI forms. Fields such as abstracts, purposes, and keywords are saved directly to the underlying PostgreSQL database. The application's failure to sanitize these parameters before database insertion or HTML rendering creates a stored cross-site scripting (XSS) pathway.
When a high-privilege user or administrator browses to the metadata details of a poisoned resource, the payload executes. Since the script executes within the victim's validated origin, it bypasses authorization restrictions without relying on cookie extraction. This vulnerability is cataloged as CWE-79, representing improper neutralization of input during web page generation.
The root cause of CVE-2024-27091 resides in GeoNode's integration of Django's template engine. Django templates are secure by default because they automatically HTML-escape dynamic variables. However, developers can override this safety feature using the |safe filter. The |safe filter explicitly instructs the rendering engine that the variable contents are pre-sanitized and can be rendered directly as raw markup.
In affected versions, the template file geonode/templates/metadata_detail.html used the |safe filter on multiple user-controlled attributes. This included resource.abstract, keyword.name, resource.constraints_other, resource.purpose, resource.data_quality_statement, and resource.supplemental_information. No backend sanitization step occurred before the templates rendered these fields, making them highly vulnerable to payload injection.
Because the rich-text WYSIWYG editor's client-side protections were the only barrier against script injection, attackers could easily bypass them. An attacker could issue direct API requests or bypass frontend input validation entirely. The backend did not enforce server-side validation or tag parsing, allowing database tables to store dangerous raw HTML wrappers.
The vulnerability was patched in commit e53bdeff331f4b577918927d60477d4b50cca02f by implementing a server-side HTML sanitization layer. The developers introduced a custom Django template filter named sanitize_html in geonode/base/templatetags/sanitize_html.py. This filter relies on the nh3 Python library, which leverages the Rust-based ammonia library to guarantee performant and secure HTML purification.
Below is the implementation of the custom filter from the official patch:
from django import template
from django.conf import settings
import nh3
from django.utils.encoding import force_str
register = template.Library()
@register.filter(name="sanitize_html")
def sanitize_html(value):
value = force_str(value)
nh3_config = getattr(
settings,
"NH3_DEFAULT_CONFIG",
{
"tags": {"b", "a", "img", "p", "ul", "li", "strong", "em", "span"},
},
)
return nh3.clean(value, **nh3_config)The custom filter parses the HTML structure and strips all tags and attributes not defined in the safe whitelist. Elements like <script>, <iframe>, and event handlers (e.g., onerror) are completely removed. In the metadata templates, all instances of user-controlled variables were modified to chain this sanitization filter ahead of the |safe filter:
<!-- Vulnerable Template Implementation -->
<dd>{{ resource.abstract|safe }}</dd>
<!-- Patched Template Implementation -->
<dd>{{ resource.abstract|sanitize_html|safe }}</dd>An attacker can exploit this vulnerability to achieve full account takeover of any platform administrator who views the compromised metadata page. Although GeoNode sets session cookies with the HttpOnly and Secure attributes, which blocks direct extraction via document.cookie, the execution of arbitrary JavaScript within the application's origin allows attackers to perform complex state-changing actions on behalf of the victim.
The attack begins when the victim loads the detail page of a modified resource. The malicious script executes and immediately reads the anti-CSRF token directly from the DOM, specifically targeting the csrfmiddlewaretoken hidden input field or parsing it from the local cookie store. Because the browser automatically attaches the victim's session cookies to requests sent to the same origin, the script is authorized to perform state-changing HTTP requests.
Once the CSRF token is obtained, the script initiates a background POST request to the email management endpoint (e.g., /account/email/change/). The payload contains the stolen CSRF token and updates the primary email address to an inbox controlled by the attacker. Since this request executes seamlessly in the background, the administrator receives no immediate alert. The attacker then triggers a standard password reset request for the admin account, receiving the reset token via the newly registered email address to complete the takeover.
The security impact of CVE-2024-27091 is classified as medium-severity with a CVSS v3.1 base score of 6.1. This score reflects an attack vector requiring low complexity and zero initial privileges, but relying heavily on user interaction. The scope change (S:C) highlights that the script execution context can compromise resource parameters beyond the immediate data layer.
A successful compromise can lead to a full takeover of administrative sessions. In a geospatial environment, an administrative takeover provides the adversary with total access to maps, imagery datasets, secure databases, and internal infrastructure configurations. Attackers could manipulate geographical boundary data, delete spatial databases, or use the compromised platform to launch downstream attacks against public GIS map users.
While the EPSS score of 0.00376 indicates a low probability of immediate automated exploitation in the wild, targeted environments face a high threat. This flaw acts as a silent privilege escalation bottleneck. Security operations should treat it as high risk, particularly in federal, academic, or corporate spatial systems where GeoNode serves as a central data repository.
The primary remediation path for CVE-2024-27091 is upgrading all GeoNode deployments to version 4.2.3 or later. This upgrade modifies the system dependencies to require the Rust-backed nh3 HTML sanitizer, ensuring all stored user-supplied metadata fields are processed before rendering. For systems running older, unpatched releases where an immediate upgrade is not feasible, administrators must apply manual code-level mitigations.
To implement a manual hotfix, security engineers should copy the custom sanitize_html.py tag filter file from the official patch commit and install the nh3 library (pip install nh3). All template files referencing |safe filters must be reviewed. Apply the |sanitize_html filter preceding any |safe filter as demonstrated in the patch diff.
In addition to patching, deploying a strong Content Security Policy (CSP) is highly recommended. Enforcing a policy such as Content-Security-Policy: default-src 'self'; script-src 'self'; prevents inline scripts and event handlers from executing. This defense-in-depth measure completely neutralizes the threat of stored XSS, even if sanitization is bypassed or omitted on future templates.
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
GeoNode GeoSolutions Group | >= 3.2.0, < 4.2.3 | 4.2.3 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-79 (Improper Neutralization of Input During Web Page Generation) |
| Attack Vector | Network (AV:N) |
| CVSS v3.1 | 6.1 (Medium) |
| Exploit Status | Proof of Concept / Code Analysis Available |
| EPSS Score | 0.00376 (Percentile: 29.75%) |
| KEV Status | Not Listed |
The software does not neutralize or incorrectly neutralizes user-controlled input before it is placed in output that is used as a web page that is served to other users.
The DIRAC PilotManager component contains combined security weaknesses: a SQL injection vulnerability (CWE-89) in the PilotAgentsDB database interaction layer, and an improper access control configuration (CWE-284) within the default authorization structure. A low-privilege authenticated attacker can bypass intended authorization checks to run administrative commands, manipulate grid job tracking records, and execute arbitrary SQL statements against the backend database.
An authentication bypass in the SiYuan personal knowledge management system before version 3.7.0 exposes a dynamic icon rendering endpoint. This endpoint processes client-supplied Go template directives. By submitting a crafted request, an unauthenticated remote attacker can leverage registered database template functions to execute arbitrary read-only SQL queries and exfiltrate workspace contents.
CVE-2026-54069 is a critical authentication bypass vulnerability in the SiYuan Note personal knowledge management system. The flaw is located in the HTTP server's middleware handling API authorization, which unconditionally trusts requests carrying a 'chrome-extension://' scheme in the Origin HTTP header, granting administrative access without validating API tokens.
CVE-2026-54089 is a critical authentication bypass vulnerability in File Browser affecting instances configured with proxy-based authentication. An unauthenticated remote attacker with direct network access can impersonate arbitrary users or register new accounts by spoofing configured HTTP headers.
The malicious Cargo package 'exploration' was uploaded to the crates.io registry. During compilation or package import, the crate executes code designed to establish an outbound TCP/HTTP connection, download an external second-stage binary, and execute the binary locally on the host machine. This creates an unauthenticated remote code execution vector impacting developer environments and continuous integration pipelines.
CVE-2026-54088 is a critical command injection vulnerability in File Browser prior to version 2.63.6. When Hook Authentication is enabled, the application interpolates unsanitized credentials into a shell command, allowing unauthenticated remote code execution.