Mar 10, 2026·5 min read·3 visits
copyparty before v1.20.11 fails to sanitize SVG files under the 'nohtml' flag, enabling Stored XSS via embedded script tags in user-uploaded images.
A Stored Cross-Site Scripting (XSS) vulnerability exists in copyparty prior to version v1.20.11. The 'nohtml' volume configuration flag fails to restrict SVG images, allowing authenticated attackers with write permissions to upload malicious SVGs that execute arbitrary JavaScript when viewed by other users.
copyparty operates as a portable file server supporting volume-specific configuration flags to manage client interactions. The nohtml volume flag is implemented to secure volumes containing untrusted user uploads. When active, this flag instructs the server to serve potentially dangerous web documents as plaintext, neutralizing active content and preventing script execution in the client browser.
Prior to version v1.20.11, the nohtml flag failed to identify and neutralize SVG (Scalable Vector Graphics) files. The W3C SVG specification natively supports the inclusion of executable JavaScript via the embedded <script> element. Because the application processes these files without stripping the active content or overriding the content type, the system exposes a Stored Cross-Site Scripting (XSS) attack surface (CWE-79).
The vulnerability is triggered when a user interacts with the malicious file hosted on the server. Because the execution occurs within the context of the copyparty server's origin, the script assumes the privileges and session state of the victim interacting with the resource.
The vulnerability stems from flawed MIME type validation logic within the copyparty/httpcli.py module. The original implementation utilized a simplistic substring check to determine if a requested file should be stripped of its active execution context. The application verified if the string html was present in the resolved MIME type of the requested file.
SVG files resolve to the standard MIME type image/svg+xml. Because this MIME type lacks the html substring, the server's validation check evaluates to false. Consequently, the application bypasses the defensive forced-plaintext conversion and serves the file with its original, executable MIME type.
Modern web browsers strictly adhere to the provided MIME type. When the browser receives a file labeled image/svg+xml, it initializes an XML parser to render the document structure. During this parsing phase, the browser evaluates and executes any <script> elements present within the XML tree, leading directly to arbitrary JavaScript execution.
The vulnerable code path in copyparty/httpcli.py demonstrates the inadequate MIME type verification. The implementation applied a plaintext override exclusively if the exact substring html was detected in the file's MIME type.
# Vulnerable implementation in httpcli.py
if "nohtml" in self.vn.flags and "html" in mime:
mime = "text/plain; charset=utf-8"The remediation introduced in commit 1c9f894e149b6be3cc7de81efc93a4ce4766e0e5 transitions the security model from a reactive blacklist to an aggressive, regex-based MIME allow-list. The server now evaluates the MIME type against the pattern html|script|tension|wasm|xml. Any MIME type containing these strings, which includes the xml portion of image/svg+xml, triggers the defensive remapping.
# Patched logic forces unsafe types to plaintext or octet-stream
if "nohtml" in self.vn.flags and re.search(r"html|script|tension|wasm|xml", mime):
if "text/" in mime or "xml" in mime:
mime = "text/plain; charset=utf-8"
else:
mime = "application/octet-stream"Furthermore, the patch implements defense-in-depth by injecting the X-Content-Type-Options: nosniff HTTP header globally. This prevents browsers from overriding the safe text/plain designation through client-side MIME sniffing algorithms.
Exploitation requires the attacker to possess write access to a copyparty volume. The authorization requirement satisfies the Privileges Required (PR:L) metric in the CVSS scoring. The attacker constructs a valid SVG XML document containing a malicious JavaScript payload enclosed within standard <script> tags.
<svg xmlns="http://www.w3.org/2000/svg">
<script>alert('Execution Context: ' + document.domain);</script>
<rect width="100" height="100" fill="red" />
</svg>The attacker uploads this payload to the target volume. The attack remains dormant until a victim navigates to the file via the copyparty web interface or a direct link. The requirement for a victim to browse to the specific file satisfies the User Interaction (UI:R) metric.
Upon rendering the response, the victim's browser executes the JavaScript payload. The attacker achieves arbitrary code execution within the security context of the victim's session.
The direct impact of CVE-2026-30974 is the complete compromise of the victim's session integrity on the copyparty server. Because the JavaScript executes within the application's origin, the script bypasses the Same-Origin Policy (SOP) restrictions that normally isolate distinct web applications.
The attacker's code operates with the identical authorization level as the victim. If an administrator views the malicious SVG, the script can leverage the administrator's session tokens to perform privileged actions. These actions include modifying server configurations, deleting sensitive files from protected volumes, or exfiltrating data to an external command-and-control server.
The vulnerability receives a CVSS v3.1 base score of 4.6 (Medium). The score is constrained by the necessity for pre-existing write access to the volume and the requirement for explicit victim interaction to trigger the payload execution. Despite the medium quantitative score, the qualitative risk is substantial for instances hosting highly privileged administrative accounts.
The definitive remediation for this vulnerability is upgrading the copyparty instance to version v1.20.11 or later. This release incorporates the comprehensive MIME type filtering logic, the global nosniff header, and architectural segregations for UI assets. System administrators must apply this update immediately to instances exposing public or untrusted upload directories.
Administrators must verify their volume configurations post-update. Volumes intended for untrusted user content must have the nohtml flag explicitly declared in the volume configuration block. The patch relies on this flag being active to enforce the defensive text/plain remapping.
Version v1.20.11 introduces a secondary defense-in-depth mechanism via the noscript volume flag. Administrators should enable this flag on public volumes. When active, copyparty serves content with a strict Content-Security-Policy: script-src 'none'; HTTP header, instructing compliant browsers to block all JavaScript execution regardless of the file's MIME type.
CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:U/C:L/I:L/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
copyparty 9001 | < 1.20.11 | 1.20.11 |
| Attribute | Detail |
|---|---|
| Vulnerability Type | Stored Cross-Site Scripting (CWE-79) |
| CVSS v3.1 Score | 4.6 (Medium) |
| Attack Vector | Network |
| Privileges Required | Low (Write Access) |
| User Interaction | Required |
| CISA KEV Status | Not Listed |
The application does not adequately neutralize user-controlled input before placing it in output that is used as a web page.