CVE-2026-57149
Executive Summary
CVE-2026-57149 is a critical code injection vulnerability (CWE-95) in the plone.app.portlets package, specifically within the Classic portlet (plone.app.portlets.portlets.classic). The flaw arises because user-supplied template and macro fields are used to construct a TALES path expression that is evaluated by the TAL path() helper, allowing an authenticated user with permission to add or edit a Classic portlet to inject and execute arbitrary code in the context of the Plone server process. With a CVSS score of 9.9, this represents a severe privilege escalation and remote code execution risk for Plone deployments running affected versions.
This record — and 170,000+ others — are available via the ValtersIT API. One endpoint replaces five: NVD + GitHub CVE + CISA KEV + EPSS + Nuclei + Exploit-DB, unified.
No signup required
Technical Analysis
The vulnerability resides in the Classic portlet implementation of plone.app.portlets, a Plone-specific user interface layer for plone.portlets. In affected versions (5.0.0 prior to 5.0.8, 6.0.0 prior to 6.0.4, and 7.0.0 prior to 7.0.2), the Classic portlet accepts user-supplied input for its template and macro fields. These fields are then combined into a TALES (Template Attribute Language Expression Syntax) path expression, which is subsequently evaluated by the TAL path() helper.
The core issue is that the input is interpreted as a full TALES expression rather than being restricted to a simple path traversal. TALES is a powerful expression language used in Zope and Plone that supports not only attribute traversal but also the invocation of methods, access to Python built-ins, and potentially the execution of arbitrary code via expressions such as python: prefixes. Because the Classic portlet constructs a TALES path expression from user input and passes it to the path() helper, an attacker can craft a value that breaks out of the intended path traversal context and injects an arbitrary TALES expression. When evaluated, this expression can execute Python code with the privileges of the Plone process.
The attack surface is significant: any authenticated user who can configure a Classic portlet can exploit this flaw. According to the NVD description, the default role map grants the plone.app.portlets.ManageOwnPortlets permission to regular users, allowing them to add and configure portlets on their personal dashboards. This means that a low-privileged authenticated user can trigger the vulnerability without any special administrative access. The CVSS vector (AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H) confirms a network-exploitable, low-complexity attack requiring only low privileges, with no user interaction, and a scope change that impacts confidentiality, integrity, and availability at a high level.
The mechanism is a classic case of code injection (CWE-95) via an expression language. The path() helper in TAL is designed to evaluate TALES path expressions, but when the input is not properly sanitized or constrained to a limited path syntax, it can be abused to execute arbitrary expressions. The patch in versions 5.0.8, 6.0.4, and 7.0.2 presumably restricts the input to a safe subset or prevents the evaluation of arbitrary TALES expressions. However, no patch details or source code references are provided in the intelligence data, so the exact fix remains unclear.
Exploitation Scenarios
Based on the NVD description, the following attack chain is inferred at the vulnerability-class level. No public proof-of-concept is available, and the attack steps are derived from the described flaw.
Reconnaissance/Target Identification: An attacker identifies a Plone instance running an affected version of
plone.app.portlets. This can be done by fingerprinting the Plone version via HTTP headers, error pages, or known file paths. The attacker must have valid credentials for an authenticated account—at minimum, an account with the default role map that permits adding or editing portlets on a personal dashboard.Triggering the Flaw: Once authenticated, the attacker navigates to a page where portlets can be managed (e.g., the personal dashboard). They add a new Classic portlet (
plone.app.portlets.portlets.classic) or edit an existing one. The portlet configuration form includes fields for template and macro. The attacker supplies a crafted value in one of these fields. This value is designed to escape the intended path traversal and inject an arbitrary TALES expression. For example, instead of a simple path likehere/foo, the attacker might supply a TALES expression that invokes Python code. The exact syntax is not provided in the NVD description, but it would leverage TALES features such as thepython:expression type or method calls.Payload/Execution Method: The crafted input is used by the Classic portlet to build a TALES path expression, which is then evaluated by the TAL
path()helper. Because the input is interpreted as a full TALES expression, the attacker's payload is executed as code in the context of the Plone process. This could allow the attacker to run arbitrary system commands, read or write files, or access sensitive data. The execution occurs server-side with the privileges of the Plone process, which typically runs as a dedicated user but may have access to configuration files, databases, and other resources.Post-Exploitation Impact: Successful exploitation results in code execution in the context of the Plone process. This is a privilege escalation across the trust boundary between an authenticated web user and the server-side process. The attacker can achieve full compromise of the Plone application, including access to the underlying operating system, depending on the process privileges. They could install backdoors, exfiltrate data, pivot to internal networks, or disrupt services.
No public exploit code or proof-of-concept is available, and the attack chain is inferred from the vulnerability class and the NVD description.
Impact Assessment
The CVSS score of 9.9 reflects a critical severity vulnerability. The vector CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H indicates:
- Attack Vector (AV:N): Exploitable remotely over the network.
- Attack Complexity (AC:L): Low complexity; no specialized conditions required.
- Privileges Required (PR:L): Low privileges; any authenticated user with default portlet management rights.
- User Interaction (UI:N): No user interaction needed.
- Scope (S:C): Scope change; the vulnerability in the portlet component impacts the entire Plone server and underlying host.
- Confidentiality (C:H): High impact; sensitive data can be accessed.
- Integrity (I:H): High impact; data can be modified.
- Availability (A:H): High impact; service can be disrupted.
The blast radius includes any Plone site running affected versions of plone.app.portlets. Because the default configuration grants portlet management to regular users on their personal dashboards, the attack surface is broad—any authenticated user, including low-privileged accounts, can exploit the flaw. In multi-tenant or community-oriented Plone deployments, this could lead to widespread compromise. The impact is severe: full code execution on the server, leading to potential data breaches, ransomware deployment, or use as a pivot point for further attacks.
Detection Guidance
Sigma Rule
title: Plone Classic Portlet TALES Code Injection (CVE-2026-57149)
id: 3a4b5c6d-7e8f-9a0b-1c2d-3e4f5a6b7c8d
status: experimental
description: Detects attempts to exploit CVE-2026-57149 by injecting malicious TALES expressions into the Classic portlet template or macro fields.
author: Threat Intelligence
date: 2026-01-01
logsource:
category: webserver
product: plone
detection:
selection:
cs-method: 'POST'
cs-uri-query|contains:
- 'plone.app.portlets.portlets.classic'
- 'template'
- 'macro'
cs-uri-query|re:
- '(?i)python\s*:'
- '(?i)path\s*\('
- '(?i)modules/'
- '(?i)__import__'
condition: selection
falsepositives:
- Legitimate administrative configuration of portlets with complex TALES expressions.
level: high
tags:
- attack.t1190
- cve.2026.57149
YARA Rule
rule CVE_2026_57149_Plone_Classic_Portlet_TALES_Injection
{
meta:
description = "Detects TALES code injection attempts in Plone Classic portlet (CVE-2026-57149)"
author = "Threat Intelligence"
date = "2026-01-01"
reference = "https://nvd.nist.gov/vuln/detail/CVE-2026-57149"
severity = "critical"
strings:
$tales1 = "python:" ascii nocase
$tales2 = "path(" ascii nocase
$tales3 = "__import__" ascii nocase
$tales4 = "modules/" ascii nocase
$portlet = "plone.app.portlets.portlets.classic" ascii nocase
$template = "template" ascii nocase
$macro = "macro" ascii nocase
condition:
$portlet and ($template or $macro) and any of ($tales*)
}
Suricata IDS Rule
alert http any any -> any any (msg:"CVE-2026-57149 Plone Classic Portlet TALES Code Injection Attempt"; flow:to_server,established; content:"POST"; http_method; content:"plone.app.portlets.portlets.classic"; http_uri; content:"template"; http_uri; content:"python:"; http_client_body; nocase; content:"path("; http_client_body; nocase; reference:cve,2026-57149; classtype:attempted-admin; sid:10000001; rev:1;)
Elastic Detection
network where
http.request.method == "POST" and
http.request.uri : "*plone.app.portlets.portlets.classic*" and
(http.request.body : "*python:*" or http.request.body : "*path(*" or http.request.body : "*__import__*")
Splunk SPL Query
index=web sourcetype=access_combined
| search method=POST uri="*plone.app.portlets.portlets.classic*"
| search form_data="*python:*" OR form_data="*path(*" OR form_data="*__import__*" OR form_data="*modules/*"
| stats count by src_ip, uri, form_data
| where count > 0
Wazuh OSSEC Rule
<group name="plone,cve-2026-57149,">
<rule id="100001" level="12">
<decoded_as>web-accesslog</decoded_as>
<url>plone.app.portlets.portlets.classic</url>
<regex>python:|path\(|__import__|modules/</regex>
<description>CVE-2026-57149: Plone Classic portlet TALES code injection attempt detected</description>
<mitre>
<id>T1190</id>
</mitre>
<group>cve_2026_57149,</group>
</rule>
</group>
Mitigation & Patch Guidance
Patch confidence: 0/4 (UNPATCHED — no patch evidence from any tracked source). The NVD description states the problem has been patched in plone.app.portlets 5.0.8, 6.0.4, and 7.0.2, but no patch sources or vendor advisories are available in the provided intelligence.
Immediate Mitigations:
- Restrict who can manage portlets: remove the
plone.app.portlets.ManageOwnPortletspermission from untrusted roles. By default, this permission is granted to regular users for their personal dashboards; revoking it prevents low-privileged users from adding or editing portlets. - Limit "Manage portlets" to trusted administrators only. Ensure that only the Manager and Site Administrator roles have this capability.
- If the Classic portlet is not needed, unregister it so it cannot be added. This requires editing a
portlets.xmlfile in your own code to remove the portlet registration. - Consider disabling the Classic portlet entirely if it is not essential for business operations.
- Restrict who can manage portlets: remove the
Patch/Upgrade Steps:
- Upgrade
plone.app.portletsto version 5.0.8, 6.0.4, or 7.0.2 depending on your Plone version. These versions contain the fix. Since patch confidence is 0/4, verify the integrity of the patch from official Plone sources before applying. - After upgrading, test portlet functionality and ensure that the Classic portlet no longer accepts arbitrary TALES expressions.
- If you cannot upgrade immediately, apply the workarounds above as a temporary measure.
- Upgrade
Long-Term Hardening:
- Adopt a principle of least privilege for portlet management. Regularly review role mappings and permissions.
- Monitor for suspicious TALES expressions in HTTP requests, especially those containing
python:,path(,__import__, ormodules/. - Implement Web Application Firewall (WAF) rules to block requests containing suspicious TALES syntax in portlet management endpoints.
- Keep Plone and all add-ons up to date with security patches. Subscribe to Plone security announcements.
- Conduct regular security audits and penetration testing of Plone deployments, focusing on authenticated user capabilities.
References
- NVD Entry: https://nvd.nist.gov/vuln/detail/CVE-2026-57149
- Plone Security Advisory (if available): https://plone.org/security
- CWE-95: Improper Neutralization of Directives in Dynamically Evaluated Code ('Eval Injection'): https://cwe.mitre.org/data/definitions/95.html
- Plone.app.portlets GitHub repository: https://github.com/plone/plone.app.portlets
- TALES documentation: https://zope.readthedocs.io/en/latest/zope2book/AppendixC.html
No threat actor campaigns or exploit-in-the-wild evidence are currently available for this CVE. It is not listed in CISA KEV, and no public PoC or exploit code has been observed.
What is this? Security researchers use these exact search queries on Shodan.io (a search engine for internet-connected devices) to find vulnerable systems globally. You can copy these dorks to see if your organization's IP space is exposed.