Jul 18, 2026·7 min read·0 visits
A stored XSS vulnerability exists in Plone's REST API and textfield components where attackers can bypass HTML sanitization by spoofing input MIME types as 'text/x-html-safe'. Upgrading plone.restapi and plone.app.textfield is required to mitigate this flaw.
A stored Cross-Site Scripting (XSS) vulnerability exists within plone.restapi, the REST API package for Plone content management system. By supplying a spoofed input MIME type (text/x-html-safe), an attacker can mislead the rendering layer (plone.app.textfield) into assuming that the supplied content is already sanitized. This causes the system to skip the safe_html transform, allowing arbitrary JavaScript to execute in the victim's browser when they view the compromised page.
Plone is an open-source, Python-based content management system (CMS) widely used in enterprise and public sector environments. The plone.restapi package exposes REST endpoints for content CRUD operations, forming the core data-exchange layer for modern Plone frontends. Within this architecture, rich text fields are managed by the plone.app.textfield library, which handles raw storage, transformation, and output rendering.
A high-impact stored Cross-Site Scripting (XSS) vulnerability exists when deserializing and rendering user-supplied rich text. The core security flaw involves a trust boundary violation where the REST API deserializer blindly accepts client-supplied MIME types. By declaring input data as already sanitized, an attacker can trick the system into skipping the necessary HTML purification steps.
The vulnerability is classified under CWE-80: Improper Neutralization of Script-Related HTML Tags in a Web Page. If an authenticated user with permission to add or modify content submits a crafted JSON request, they can embed arbitrary JavaScript code that executes in the browsers of other users who view the affected page. This can lead to session hijacking, credential theft, and unauthorized actions within the CMS context.
The root cause of this vulnerability lies in the optimization and serialization architecture of plone.app.textfield. Plone designates the custom MIME type text/x-html-safe to signal that HTML markup has successfully passed through the system's sanitation engine and is safe to render. The rendering pipeline uses the RichTextValue.output_relative_to method to convert the raw stored format into the target output format, relying on an ITransformer adapter.
In vulnerable versions of plone.app.textfield, an optimization check was introduced in value.py. This check compared the declared input mimeType of a field directly against the requested outputMimeType. If these two values matched, the rendering engine assumed that the markup was already in the desired final format and skipped the entire transformation process, returning the raw content unchanged.
This shortcut created a critical security flaw. If a RichTextValue object was initialized with both mimeType and outputMimeType set to text/x-html-safe, the code bypassed the safe_html transform registry completely. Because Plone templates render rich text fields using the Zope Page Templates structure modifier, HTML entity escaping is disabled, allowing raw browser-executable scripts to be rendered directly into the Document Object Model (DOM).
The vulnerability requires two distinct components to cooperate: the input deserializer (plone.restapi) and the storage rendering layer (plone.app.textfield). First, when a user posts new content, the REST API deserializer parses the incoming JSON request. In vulnerable versions, the deserializer extracted the user-supplied content-type value directly from the JSON body without validation and used it to construct the internal RichTextValue object.
Once saved in the Zope Object Database (ZODB), the malicious payload is stored permanently. When a standard user requests the page, the rendering engine calls output_relative_to(). Because both the stored mimeType and the requested outputMimeType are evaluated as text/x-html-safe, the comparison evaluates to true, executing the shortcut path and delivering the unsanitized script block directly to the browser.
The following diagram illustrates the vulnerable execution flow where user-supplied content bypasses the safety transforms:
The vulnerability is resolved via a two-layer defense-in-depth approach. At the input layer, the plone.restapi deserializer was updated to prevent external API requests from declaring the text/x-html-safe MIME type. If an incoming REST API payload attempts to set "content-type": "text/x-html-safe", the deserializer raises a ValueError exception, completely blocking external input spoofing attempts.
However, API-level blocking does not protect against existing database entries or direct programmatic instantiation of RichTextValue objects in custom add-ons. To address this, the second layer of the patch modifies plone.app.textfield's rendering logic in value.py. The comparison shortcut is restricted so that it will never apply if the requested output is safe HTML. If both input and output types are text/x-html-safe, the input type is overwritten to text/html to force the sanitization transform.
The patched implementation also introduces an in-memory cloning mechanism. If both input and output types are declared as safe, the code overrides the input type to text/html and forwards a clone of the value object to the transformer. Since RichTextValue is a ZODB persistent object, using __new__ to clone the object in memory allows the transform parameters to be updated dynamically without triggering unwanted database write operations.
An attacker must possess credentials for a low-privileged account that has permissions to create or modify content containing a rich text field, such as a contributor or editor. The attack is carried out over HTTP/HTTPS by interacting directly with the Plone REST API endpoints. Since the vulnerability is stored, it requires zero active user interaction from the target victim beyond navigating to the compromised resource.
To execute the exploit, the attacker first requests an authentication token by posting credentials to the @login endpoint. Once authenticated, they submit a POST or PATCH request targeting a specific content URL. The request payload contains a JSON structure representing the rich text field, where the data parameter holds the malicious payload, and the content-type is explicitly set to the spoofed type.
The payload can leverage various HTML tags and event handlers, such as <img src=x onerror=alert(document.cookie)> or standard inline <script> tags. Once the API accepts the payload, it writes it directly to the backend storage. When administrative users or general site visitors load the affected page, their browsers process the raw, unescaped scripts, allowing the attacker to steal cookies, extract CSRF tokens, or modify site configurations on behalf of the victim.
Remediation requires upgrading both the plone.restapi and plone.app.textfield packages to their respective patched versions. For deployments running Plone 6.0 or 6.2, administrators must ensure that plone.restapi is updated to at least 9.15.6 or 10.0.1. Concurrently, plone.app.textfield must be upgraded to 2.0.2 (for Plone 6.0), 3.0.2 (for Plone 6.1), or 4.0.1 (for Plone 6.2).
Upgrading the libraries prevents future injection attempts but does not automatically remediate legacy payloads already stored in the Zope Object Database (ZODB). System administrators should run a diagnostic script in the Zope python shell to identify objects containing spoofed RichTextValue fields. The cleanup script locates any persistent field instance where mimeType is set to text/x-html-safe and changes it back to standard text/html to force sanitization on subsequent render requests.
In addition to applying application patches, network security teams can deploy Web Application Firewall (WAF) rules to detect and drop spoofed payloads at the perimeter. Rules should inspect incoming JSON payloads destined for Plone API endpoints and trigger blocks when detecting attempts to set content-type to text/x-html-safe. This provides immediate mitigation while administrators schedule downtime to perform full system updates and ZODB database cleanup.
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
plone.restapi Plone Foundation | < 9.15.6 | 9.15.6 |
plone.restapi Plone Foundation | == 10.0.0 | 10.0.1 |
plone.app.textfield Plone Foundation | < 2.0.2 | 2.0.2 |
plone.app.textfield Plone Foundation | >= 3.0.0, < 3.0.2 | 3.0.2 |
plone.app.textfield Plone Foundation | == 4.0.0 | 4.0.1 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-80 (Improper Neutralization of Script-Related HTML Tags) |
| Attack Vector | Network (AV:N) |
| CVSS v3.1 Score | 4.3 (Medium) |
| Attack Complexity | Low (AC:L) |
| Privileges Required | Low (PR:L) |
| User Interaction | None (UI:N) |
| Exploit Status | PoC (Proof of Concept Available) |
The software does not neutralize or incorrectly neutralizes user-controlled input before rendering it as HTML.
An untrusted search path vulnerability in the GlobalDatabasePlugin component of the AWS Advanced JDBC Wrapper for Amazon Aurora PostgreSQL allows authenticated, low-privilege database users to hijack administrative session queries. By defining a custom function in a writable schema such as the public schema, an attacker can hijack queries executed automatically during driver-level topology detection. When a highly privileged database user connects to the database utilizing an affected version of the wrapper, the custom function executes under their security context, enabling remote privilege escalation to rds_superuser.
CVE-2026-27771 represents a critical security flaw in Gitea and Forgejo (up to and including version 1.26.1) involving missing authorization checks (CWE-862). Unauthenticated remote attackers can query, enumerate, and download private container images from the OCI-compliant container registry. Additionally, unauthorized users can retrieve private or internal source repository URLs via the Composer package registry metadata API. A public proof-of-concept exists, and threat metrics indicate highly active scanning and exploitation risks.
A missing authorization vulnerability in the Formie plugin for Craft CMS prior to version 3.1.28 allows low-privileged Control Panel users to read and modify sensitive administrative settings, configuration options, and third-party integrations.
CVE-2026-53598 is a directory traversal and arbitrary file read vulnerability in Microsoft Prompty ecosystem loaders across multiple languages. Prior to version 2.0.0-beta.2, the loaders resolved `${file:...}` reference strings inside frontmatter configuration blocks without enforcing that the target file paths resided within authorized directories. This deficiency allows an attacker-controlled configuration file to read sensitive operating system and application files through absolute paths, directory traversal, or symbolic link escapes. The issue is addressed across the Python, C#, Node.js/TypeScript, and Rust ecosystems.
A directory traversal vulnerability exists in the copy subcommand of the proot-distro utility. Due to incomplete path sanitization, local attackers or malicious scripts can read from or write to arbitrary files outside the container rootfs, bypassing isolation barriers and potentially gaining unauthorized access or persistent execution on the host system.
An authorization bypass vulnerability in the Open Policy Agent (OPA) integration of the Skipper HTTP router allows unauthenticated remote attackers to bypass OPA policy inspection. When an incoming HTTP request declares a Content-Length exceeding Skipper's configured maxBodyBytes limit, Skipper bypasses body parsing and forwards an empty document to OPA, while transmitting the full, uninspected payload intact to the upstream backend.