Hacking Liferay: From XSS to RCE via CAPTCHA Bypass
In this blog post, we discuss two different vulnerabilities identified by AnchorSec in the enterprise portal software, Liferay. When chained together, these vulnerabilities could be used by an unauthenticated attacker to achieve Remote Code Execution (RCE), fully compromising the Liferay application. Please note, Liferay have since released patches for these vulnerabilities and stated that the issues have been fixed in the following versions:
Liferay Portal fixed on master branch
Liferay DXP 2024.Q1.14
Liferay DXP 2024.Q4.6
Liferay DXP 2025.Q1.0
About Liferay
Liferay describes itself as a Digital Experience Platform (DXP), a more comprehensive alternative to traditional Content Management Systems and enterprise portals, with modules that support a wide range of additional functionality, such as e-commerce capabilities.
Liferay was chosen as a research target for the following reasons:
Major enterprise customers - Liferay is used by a number of large multinationals and financial institutions.
Open Source - The Liferay Portal is open source and a Community Edition is freely available.
Large attack surface - The more complex an application is and the more functionality it provides, the more ways it could be vulnerable. In this regard, Liferay is a reasonably substantial application, making it a promising target for vulnerability research.
Software version
A test installation of the Liferay Community Edition Portal (version 7.4.3.125 CE GA125) was created by AnchorSec. Though all research was performed in this test environment, Liferay would later confirm that the discovered vulnerabilities also affected the enterprise version of Liferay, Liferay DXP.
CVE-2025-4599: Cross-Site Scripting (XSS) via postMessage
While searching the Liferay Portal files for strings of interest, the following code was discovered:
As shown above, the JavaScript returned by this page registers the function handleIframeMessage as a handler for the message event. The handleIframeMessage function uses the data contained within the received message to set the value of the HTML inside the portlet-body element.
This is a classic postMessage-based XSS vulnerability. Because the handleIframeMessage function does not verify the origin of the message, a malicious message sent from a different origin can be used to inject arbitrary HTML/JavaScript into the Liferay page.
After some further investigation, it was found that the vulnerable JavaScript block was returned by the following URL path:
As proof-of-concept, an example attack page was created: "fragments-postmessage-poc.html".
Steps to reproduce:
Host the fragments-postmessage-poc.html file on a separate origin from the target Liferay installation.
Modify the targetLiferayHost value inside fragments-postmessage-poc.html so that it points to the target Liferay instance. In our test environment, Liferay was hosted on http://localhost:8009.
Sign into the target Liferay instance as an administrator.
Navigate to the fragments-postmessage-poc.html attack page in the same browser that was used to sign into Liferay.
Press the "click me!" button to launch the XSS attack.
The attack page should open the vulnerable Liferay fragment preview page in a different tab.
The attack page will repeatedly send XSS payloads to the newly opened Liferay page. These payloads should produce an alert box, as shown in the screenshot below:
This vulnerability was reported to Liferay, who accepted the finding and applied for a CVE number, with the vulnerability being designated as CVE-2025-4599.
It should be noted that the CVSS 4.0 vector string associated with this CVE number was created by Liferay itself and does not fully correlate with AnchorSec’s understanding of the issue. For example, the Privileges Required metric is currently recorded as “High”, while the attack can actually be executed by an unauthenticated attacker; only the target victim needs to be signed into the Liferay application. Thus the severity could be considered higher than the assigned CVSS score.
CVE-2025-4604: CAPTCHA Bypass for Gogo Shell
Having identified an XSS vulnerability in the Liferay administration panel (see above), we were keen to understand the potential impact. In particular, we wanted to understand whether such an XSS issue could be used to achieve Remote Code Execution (RCE).
Looking through the administrator functionality, the Gogo shell seemed to be the most promising target. While the principal purpose of the Gogo shell is to allow administrators to interact with the OSGi framework, the shell also supports some basic file system commands, such as “cat” and “ls”.
It was noted that the Gogo shell also supported the Eclipse Equinox “exec” and “fork” commands, meaning that it was possible to execute commands that were not directly supported. For example, it was possible to use the “exec” command to invoke the “curl” command, as shown below:
In addition to the method described above, there are other ways an attacker might leverage the Gogo shell to achieve arbitrary code execution on the Liferay server, as the shell can be used to install and start OSGi bundles.
As we understand it, this is the intended functionality of the Gogo shell and does not constitute a vulnerability in its own right. The Liferay documentation does warn that access to the Gogo shell should be granted sparingly:
Having investigated the functionality of the Gogo shell, we knew that if it was possible to create an XSS payload which submitted a malicious value to the shell, then it would be possible to execute malicious commands on the OS, potentially escalating from XSS to RCE.
However, we encountered a slightly unusual barrier to exploitation: the Gogo shell input form is protected by a CAPTCHA.
Every time a command is submitted, the user must solve the CAPTCHA and enter the correct value in the text verification field. If the CAPTCHA is not entered correctly, then the Gogo shell will not execute the command.
In order for our XSS payload to exploit the Gogo shell, it was therefore necessary to find a way around the CAPTCHA.
One initial idea was that it might be possible to simply disable the CAPTCHA — to create an XSS payload which would first turn CAPTCHAs off, and then submit a command to the Gogo shell. However, the Gogo shell CAPTCHA could not be disabled using the usual methods:
(From the Liferay documentation)
This page contained a number of CAPTCHA related settings, including the URLs used by the reCAPTCHA engine:
Consequently, it was possible to create an XSS payload that would bypass the Gogo shell CAPTCHA by reconfiguring the CAPTCHA settings so that the Verify URL pointed towards an attacker-controlled server.
This method was demonstrated using the following attack server files:
webserver-xss-to-rce.py – a simple Python web server, which serves the “xss-to-rce.html” file and responds to the reCAPTCHA verification request.
xss-to-rce.html – the attack page which contains the XSS payload.
The xss-to-rce.html attack page uses the following steps to escalate from XSS to RCE:
The postMessage XSS attack is used to inject malicious JavaScript into the vulnerable Liferay page.
The injected JavaScript creates an iframe containing the CAPTCHA settings page.
The injected JavaScript modifies the CAPTCHA settings so that the CAPTCHA engine used is "reCAPTCHA" and that "reCAPTCHA Verify URL" points to the attack server.
The injected JavaScript creates an iframe containing the Gogo shell page.
The injected JavaScript modifies the Gogo shell form to include a "g-recaptcha-response" parameter and submits a command to be executed by the Gogo shell.
This causes the Liferay application to send a request to the attack server, requesting confirmation that the supplied CAPTCHA value is correct.
The webserver-xss-to-rce.py attack server sends a positive response to the CAPTCHA verification request, indicating to the Liferay server that the supplied CAPTCHA value is correct.
The Liferay application executes the supplied Gogo shell command.
The injected JavaScript restores the original CAPTCHA settings.
In the example screenshot below, this method was used by the xss-to-rce.html attack page to successfully execute the command "ls /etc/".
According to Liferay, this Gogo shell CAPTCHA bypass technique was fixed in Liferay DXP 2025.Q2.0 and has been fixed on the master branch of Liferay Portal.
As mentioned above, this feels like a slightly atypical way to utilise a CAPTCHA. CAPTCHAs are usually designed to act as an anti-automation measure, preventing spam bots and brute force attacks. However, the Gogo shell the administration control panel and is (in theory) only accessible to the most privileged users. If an attacker or spam bot has gained access to the Gogo shell, then a substantial security breach has already occurred.
When a piece of administrator functionality is deemed especially sensitive, then a more typical approach would be to force the user to reauthenticate, which would provide a more robust defence against this type of XSS to RCE escalation.
Final thanks
AnchorSec would like to thank Liferay for their assistance during the disclosure process. Liferay recently opened their bug bounty program to the public, which we believe demonstrates a real willingness to engage with security researchers.