CVE-2026-14480: OpenPLC Runtime v3 Arbitrary File Write
TL;DR - OpenPLC Runtime v3 is affected by a critical authenticated arbitrary file write flaw. - Authenticated users may write files to attacker-chosen paths and potentially gain code execution. - OpenPLC v3 is end-of-life; move to Runtime v4 and isolate any remaining v3 systems urgently.
Vulnerability at a Glance
| Field | Value |
|---|---|
| CVE ID | CVE-2026-14480 |
| CVSS Score | 9.9 Critical |
| Attack Vector | Unknown in the source material provided; exploitation is confirmed to require an authenticated path through the legacy web UI |
| Privileges Required | Authentication required |
| Patch Available | No specific v3 patch version identified in the cited primary sources; practical remediation is migration to OpenPLC Runtime v4 |
CVE-2026-14480 affects OpenPLC Runtime v3, also referred to as OpenPLC v3 in upstream and advisory materials. According to NVD and CISA ICS advisory content, the issue sits in the legacy web UI program-upload workflow and lets an authenticated user control where an uploaded file is ultimately written on disk.
This matters because the bug is not limited to a harmless upload directory escape. In OpenPLC v3’s build flow, malicious C++ source files written into the runtime core directory may later be compiled into the executable runtime binary during normal operator actions. That turns an arbitrary file write into potential native code execution as the OpenPLC runtime user.
What Is This Vulnerability?
At its core, CVE-2026-14480 is an improper file path handling flaw in the OpenPLC Runtime v3 web interface. The vulnerability exists because the application stores an attacker-supplied filename value, prog_file, into the Programs.File database field and later reuses that value as a filesystem destination for an uploaded file. The application does not sufficiently validate or constrain the path before writing.
The published description specifically calls out the behavior of Python os.path.join(). When one of the joined path elements is absolute, it can override the intended base path. If user-controlled input is passed through this logic without validation, an attacker can force the application to write the uploaded file to an arbitrary absolute path, as long as that destination is writable by the OpenPLC webserver process.
The second stage is what makes this vulnerability especially severe in operational technology environments. OpenPLC’s default build pipeline automatically compiles C++ source files located within the runtime core directory into the runtime binary. If an authenticated attacker uploads a malicious .cpp file into that directory, the attacker may not need a separate memory corruption bug or shell access. They only need the operator to trigger a routine compile-and-start workflow.
In practice, that means a legitimate application feature chain becomes the exploit path: upload, write to attacker-chosen path, place malicious source, wait for standard compile/start action, and execute code as the runtime user. For defenders, this is a good reminder that arbitrary file write in build-aware or plugin-aware systems often becomes code execution even when the initial bug is “just” path traversal or unsafe file placement.
Technical Notes
A simplified unsafe pattern consistent with the published behavior would look like this:
# Simplified conceptual example based on the advisory description
upload_dir = "/opt/openplc/webserver/st_files/"
user_filename = prog_file_from_db # attacker-controlled
dest = os.path.join(upload_dir, user_filename)
with open(dest, "wb") as f:
f.write(uploaded_content)
If user_filename is absolute, the effective destination may no longer remain under upload_dir:
>>> os.path.join("/opt/openplc/webserver/st_files/", "/opt/openplc/runtime/core/payload.cpp")
'/opt/openplc/runtime/core/payload.cpp'
Who Is Affected?
The primary sources provided identify OpenPLC Runtime v3 / OpenPLC v3 as affected. CISA’s advisory explicitly states that OpenPLC Runtime v3 contains the vulnerability, and the upstream OpenPLC_v3 repository is archived and marked end-of-life. No narrower affected sub-version range was provided in the cited NVD or CISA materials.
Because no granular “from version X to version Y” range was published in the source material available here, defenders should assume that OpenPLC v3 deployments are affected unless they have vendor-grade evidence to the contrary. In other words, if your environment is running any OpenPLC v3 instance based on the archived branch, treat it as vulnerable.
The remediation guidance is also important in scope assessment. The sources do not identify a fixed-in OpenPLC v3 build number. Instead, the practical migration target is OpenPLC Runtime v4 because v3 is no longer a supported branch. That means organizations with embedded or appliance-style OT deployments should inventory not only software package versions but also vendor appliances, lab controllers, or engineering test rigs that may have bundled OpenPLC v3 components.
This is particularly relevant for sectors called out by CISA, including critical manufacturing, energy, transportation systems, and water and wastewater. In those environments, even authenticated-only vulnerabilities can become high risk when shared accounts, flat OT trust zones, or weak separation between engineering workstations and control components exist.
CVSS Score Breakdown
NVD assigns CVSS v3.1 9.9 (Critical) to CVE-2026-14480. The exact vector string was not included in the research note provided, so it would be inappropriate to invent precise component values beyond what the sources support. However, the high score is consistent with the described impact: arbitrary file write with a realistic path to arbitrary native code execution in an ICS runtime context.
Even without the exact vector string in hand, several score drivers are clear from the published description. First, impact is high because successful exploitation can lead to code execution as the OpenPLC runtime user. Second, the exploit path is reliable enough to be scored near the top of the CVSS scale, especially where the product’s normal compile pipeline turns file placement into executable behavior. Third, although authentication is required, CVSS can still remain critical if the confidentiality, integrity, and availability impacts are severe enough.
Defenders should interpret the 9.9 not as a purely theoretical lab score, but as a signal that authenticated access to this product should be treated as highly sensitive. In many OT environments, local operator, maintenance, or engineering credentials are shared more broadly than intended. That makes “authenticated” a weaker barrier in practice than it might appear in a typical enterprise web app.
If your risk process depends on exact CVSS subcomponents, verify them directly in the NVD entry before populating internal dashboards. In the absence of the vector string in the current source set, the safest operational assumption is that this is a critical-impact vulnerability requiring expedited remediation or isolation.
Exploitation Status
At the time of writing, there is no confirmed public exploitation in the wild in the cited primary sources. CISA’s advisory states: “No known public exploitation specifically targeting this vulnerability has been reported to CISA at this time.” The CVE is also not listed in CISA’s Known Exploited Vulnerabilities catalog.
It is equally important to state what is not known. The source material provided does not include a public proof-of-concept URL, vendor exploit write-up, or GitHub PoC reference. Therefore, it would be inaccurate to claim a public PoC exists based on the current evidence set. The correct practitioner takeaway is: no known public exploitation reported to CISA, no PoC identified in the cited primary sources, but the exploit chain appears technically straightforward from the published description.
That nuance matters for prioritization. Lack of KEV status or published exploitation does not make this low risk, especially in OT settings. The attack requires authentication, but once an attacker has valid credentials or session access, the path from file write to code execution is clearly described. In environments with exposed engineering interfaces, reused passwords, or weak segmentation, a credentialed attacker may not face many additional barriers.
For defenders, the best assumption is that exploit development is likely feasible for capable researchers or adversaries, even if no public exploit artifact is currently documented.
How to Detect It
Detection should focus on three phases: suspicious use of the legacy web UI upload workflow, unexpected file creation outside normal upload directories, and compile/start events that may pull in newly dropped C++ source files. Because the public description names the vulnerable mechanism but does not publish a vendor log schema, defenders need to combine application, filesystem, and process telemetry rather than depend on a single indicator.
Start by identifying all OpenPLC v3 hosts and baseline their expected file paths. Any write into runtime core source directories originating from the webserver process should be treated as suspicious unless you have a documented administrative workflow that explains it. Likewise, unexpected creation of .cpp files near the runtime core immediately before a compile/start event should be investigated as a potential exploitation attempt.
On the network side, watch for authenticated POST requests to the legacy web UI program-upload function, especially when followed by compile or runtime start actions from the same source IP or user session. Because the exact endpoint naming may vary by deployment or reverse proxy setup, defenders should first review normal web logs to identify the routine upload and compile URLs used in their environment.
Technical Notes
Example filesystem hunting on Linux for suspicious source placement:
find / -type f -name "*.cpp" 2>/dev/null | grep -E "openplc|runtime|core"
Example process/file correlation using auditd concepts if enabled:
# Watch likely runtime core path for writes
auditctl -w /opt/openplc -p wa -k openplc-write-watch
# Search recent events
ausearch -k openplc-write-watch --start recent
Example log patterns to look for in web or reverse-proxy logs:
POST /<openplc-upload-endpoint> HTTP/1.1
multipart/form-data
filename="*.cpp"
POST /<openplc-compile-or-start-endpoint> HTTP/1.1
Example Sigma-style pseudo-logic for web log detection:
title: OpenPLC suspicious source upload followed by compile
status: experimental
logsource:
category: webserver
detection:
selection_upload:
cs-method: POST
cs-uri-query|contains: "upload"
selection_cpp:
request_body|contains: ".cpp"
selection_compile:
cs-method: POST
cs-uri-query|contains:
- "compile"
- "start"
condition: selection_upload and selection_cpp or selection_compile
level: high
If logs are sparse, review shell history, systemd journals, and file mtimes around compile events:
journalctl --since "2026-07-01" | grep -Ei "openplc|compile|runtime|start"
find /opt/openplc -type f -printf "%TY-%Tm-%Td %TT %p\n" | sort
Mitigation and Patching
The strongest mitigation from the available sources is clear: migrate from OpenPLC Runtime v3 to OpenPLC Runtime v4. The cited materials do not provide a fixed OpenPLC v3 version number, and the upstream v3 repository is archived and marked end-of-life. Because no supported v3 patch target was identified, there is no defensible recommendation to “stay on v3 and patch later.”
If immediate migration is not feasible, reduce exposure aggressively. CISA’s OT guidance applies directly here: keep affected systems off the public internet, isolate control networks from business networks, restrict remote access, and require secure, fully updated VPN-based access when remote administration is unavoidable. Because exploitation requires authentication, access control hardening is a meaningful short-term risk reducer, but it is not a substitute for retiring the vulnerable branch.
You should also limit who can access the legacy web UI, rotate any shared or stale credentials, and review local write permissions of the OpenPLC webserver/runtime user. Even though changing filesystem permissions may not fully eliminate exploitation risk, reducing writable paths in the runtime tree can make trivial code-placement attacks harder. Validate these changes carefully in a test environment first, since OT systems can be sensitive to permission changes.
Technical Notes
If you are managing OpenPLC from source or GitHub checkout, confirm whether you are on the archived v3 branch:
git remote -v
git branch
git status
Because the provided primary sources do not document a universal package manager command for all OpenPLC deployments, the specific upgrade command depends on how your environment installed the software. At minimum, plan and execute a migration to OpenPLC Runtime v4 from the official supported distribution path used by your organization.
For Linux teams using service controls during emergency containment, consider stopping the runtime and restricting access to the web UI until migration is complete:
sudo systemctl stop openplc
sudo systemctl disable openplc
sudo ufw deny 8080/tcp
Example temporary network restriction on a host-based firewall:
# Allow only a specific engineering subnet to reach the web UI
sudo iptables -A INPUT -p tcp --dport 8080 -s <engineering_subnet>/24 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 8080 -j DROP
Example credential hygiene and exposure reduction checklist:
- Disable internet exposure for the OpenPLC web UI
- Restrict access to approved engineering jump hosts
- Rotate all OpenPLC operator and admin credentials
- Remove shared accounts where possible
- Review writable directories owned by the webserver/runtime user
- Monitor for new .cpp files under runtime-related paths
In the absence of a v3 fixed build number, defenders should assume that remaining on v3 means remaining exposed.
References
The authoritative references for this CVE are the NVD entry, the CISA ICS advisory, and the upstream OpenPLC v3 repository status. These sources establish the product naming, vulnerability description, exploitation status statement, and the practical remediation path away from the end-of-life branch.
Because details such as exact v3 fixed versions and a public PoC were not present in the cited primary sources, they should not be assumed. If your organization needs additional implementation detail for migration, verify current OpenPLC Runtime v4 documentation directly from upstream before scheduling production OT changes.
-
NVD: CVE-2026-14480
https://nvd.nist.gov/vuln/detail/CVE-2026-14480 -
CISA ICS Advisory ICSA-26-190-01
https://www.cisa.gov/news-events/ics-advisories/icsa-26-190-01 -
CISA CSAF JSON advisory
https://raw.githubusercontent.com/cisagov/CSAF/develop/csaf_files/OT/white/2026/icsa-26-190-01.json -
OpenPLC v3 upstream repository status
https://github.com/thiagoralves/OpenPLC_v3
For further reading on DDoS protection, check out our article on comparing the best DDoS protection services for 2026. If you’re interested in securing your network, consider using a password manager like 1Password to keep your credentials safe.
This article may contain affiliate links. We earn a commission on qualifying purchases at no extra cost to you.