Cache Poisoning XSS Vulnerability in Plone CMS
All versions of CMS Plone are vulnerable to cache poisoning with an impact of a stored Cross-Site Scripting (XSS).
More specifically, Products.CMFPlone 4 series and two packages used by Plone 5 and Plone 6, plone.app.contenttypes and Products.ATContentTypes, are vulnerable.
The attack is remotely and anonymously exploitable with a low attack complexity. However, the severity depends on the web servers’ cache configuration. Patches are available for Plone 5 and Plone 6.
The XSS and OpenRedirection are possible through the Referer header, which was reflected in a href tag of any image in the image_view_fullscreen perspective. The following proof of concept (POC) alerts the victim’s cookies; more invasive attacks can be of course be facilitated.
GET /Plone/test.png/image_view_fullscreen HTTP/1.1
Clicking the href tag seen in the following server response will result in the malicious code being executed in the user’s context.
HTTP/1.1 200 OK
Cache-Control: max-age=0, s-maxage=60, must-revalidate
X-Powered-By: Zope (www.zope.org), Python (www.python.org) X-Varnish: 98381
Via: 1.1 varnish (Varnish/6.2)
<img src="http://192.168.8.129:8080/Plone/test.png/@@images/image.png" alt="test" title="test" height="359" width="783" />
As this href, including any injected malicious code, is cached, for example in Varnish, any later visitor will execute the malicious code or get redirected when clicking on the link on the page. Depending on the cache settings, the cache poisoning vulnerability can either be exploitable or unexploitable but is vulnerable by default. The impact of the cache poisoning is like a stored XSS and can be used to target other users who subsequently visit the poisoned page. The reflected XSS and OpenRedirection through the Referer header is exploitable whether the cache is enabled or disabled.
The Google inurl: operator came to good use as vulnerable sites had the image_view_fullscreen string included in the URL. Multiple websites were found vulnerable to the reflected referrer, including multiple governmental sites.
To figure out which of them were vulnerable to the cache poisoning either invasive testing could be performed, or preferably indications that a cache was in use identified – luckily, this was willingly stated in multiple server headers as seen below:
- X-Cache-Operation: plone.app.caching.moderateCaching
- X-Cache-Rule: plone.content.itemView
- X-Powered-By: Zope (www.zope.org), Python (www.python.org) X-Varnish: 98381
- Cache-Control: max-age=0, s-maxage=60, must-revalidate
- X-Cache-Rule: plone.content.itemView
- Via: 1.1 varnish
- X-Cache: HIT
Wappalyzer was also very useful to determine the extent of affected sites as it had a database of about 4000 vulnerable sites.
The following information is provided in the Plone Security Advisory GHSA-8w54-22w9-3g8f.
There are no patches available for Plone 4.x or earlier. However, Plone 5.2.7 has been released to fix vulnerable Plone versions 5-5.2.x. 6.0.0a3 has been released as well to fix vulnerable Plone 6 versions.
If no patching is available or it is not possible to patch due to individual circumstances, the following workaround can be used:
Make sure the image_view_fullscreen page is not stored in the cache.
- Login as Manager and go to Site Setup.
- Go to the ‘Caching’ control panel. If this does not exist, or ‘Enable caching’ is not checked, you should normally not be vulnerable.
- Click on the tab ‘Caching operations’.
- Under ‘Legacy template mappings’ locate the ruleset ‘Content item view’.
- From the last column (‘Templates’) remove ‘image_view_fullscreen’.
- Click on Save.
Plone Security Team took the medium severity finding very seriously, and within a week, patches and a workaround were released. Unfortunately, the vulnerability could have been discovered and remediated much earlier. Doing the code review, it was discovered that problems related to the reflected Referer header were previously pointed out by mamico on GitHub back in 2017.