CVE-2026-71268: OpenPLC Runtime v3 arbitrary file write leading to RCE
TL;DR - OpenPLC Runtime v3 has a critical arbitrary file write issue in Structured Text upload handling. - Affected teams should treat all v3 deployments as exposed until verified otherwise. - No fixed version is identified in the cited sources, so mitigation is urgent.
Vulnerability at a Glance
| Field | Value |
|---|---|
| CVE ID | CVE-2026-71268 |
| CVSS score | 9.9 Critical |
| Attack vector | Remote, via uploaded Structured Text (.st) files in the application workflow |
| Auth required | Not fully specified by NVD; practical exploitation likely requires access to the upload workflow. Defenders should assume authenticated exploitation unless their instance exposes upload functionality more broadly |
| Patch available | No confirmed patch or fixed release identified in the cited primary sources |
The immediate operational concern is that this is not just a crash or denial-of-service condition. The flaw allows attacker-controlled content to be written to attacker-controlled filesystem paths, which can be turned into code execution if the OpenPLC process can reach sensitive locations such as cron directories or SSH-related paths.
The other practical risk multiplier is called out directly in the public description: OpenPLC Runtime v3 ships with hardcoded default credentials, openplc:openplc. That does not change the root cause, but it lowers the barrier to exploitation in poorly secured deployments. If you run OpenPLC Runtime v3 anywhere reachable from less-trusted networks, treat this as high priority.
What Is This Vulnerability?
CVE-2026-71268 is a path traversal and arbitrary file write vulnerability in OpenPLC Runtime v3. According to the NVD description, the vulnerable code path is compile_program() in webserver/openplc.py. That function processes uploaded Structured Text program files and recognizes directives in the form (*FILE:path content*).
The issue arises because the application takes the attacker-supplied path value from that directive and uses it to build a destination path with os.path.join('./core', file_path) without validating that the resulting path actually stays under the intended ./core directory. In other words, the code assumes a relative path is safe, but traversal sequences like ../../../ can escape the intended directory.
That turns a normal file-generation feature into a write-anywhere primitive, subject to the permissions of the running process. If the service account can write to locations later processed by the operating system or other services, an attacker can pivot from arbitrary file write to command execution. The NVD description specifically cites cron and SSH authorized_keys as examples.
A notable implementation detail is that a path validation helper, validate_file_path(), reportedly exists elsewhere in the codebase in webserver/credentials.py, but it is not invoked by compile_program(). That matters because it indicates the problem is not merely conceptual; there was already code available that appears intended to constrain file paths, but it was not used at the sink where it mattered.
Technical Notes
A simplified representation of the vulnerable pattern looks like this:
# conceptual example based on the NVD description
dest = os.path.join("./core", file_path)
with open(dest, "w") as f:
f.write(content)
A malicious Structured Text directive could resemble:
(*FILE:../../../etc/cron.d/openplc-job * * * * * root /bin/sh -c 'id >/tmp/pwned'*)
The security failure is that joining a base directory with user input is not sufficient validation. Safe handling requires canonicalization and an enforceable check that the resolved path remains inside the approved directory tree.
Who Is Affected?
The affected product identified in the available source material is OpenPLC Runtime v3. The NVD description explicitly states “OpenPLC Runtime v3”. The linked project repository is thiagoralves/OpenPLC_v3, which corroborates the product naming.
What is not available from the cited primary material is a narrower affected range inside v3, such as “before x.y.z” or “through build n.” Because no vendor advisory or release notes were provided that bound the vulnerable versions more precisely, the most defensible statement is that OpenPLC Runtime v3 is affected, with exact bounded vulnerable sub-versions not specified in the retrieved primary sources.
That means asset owners should not wait for more precise version mapping before acting. If you have an OpenPLC Runtime v3 deployment, you should assume it is in scope until you validate either that a downstream package maintainer backported a fix or that a local hardening layer blocks exploitation.
The public references also indicate the repository is archived. That is relevant operationally because archived projects often have slower or nonexistent remediation paths. If your deployment depends on this code line, patch planning may need to include migration, isolation, compensating controls, or local source remediation instead of expecting a maintained upstream package.
Technical Notes
A quick inventory approach on Linux hosts might include:
find / -type d -iname "*OpenPLC*" 2>/dev/null
ps aux | grep -i openplc
systemctl list-units --type=service | grep -i openplc
If you maintain software inventories or SBOM-like records, search for package or repository references matching:
OpenPLC Runtime v3
thiagoralves/OpenPLC_v3
CVSS Score Breakdown
The published base score is 9.9 Critical per NVD. The full CVSS vector string was not available in the supplied NVD tool output, so it would be inaccurate to invent component values such as attack complexity, scope, or impact metrics. That limitation matters because defenders often over-read CVSS scores without checking whether the vector details are actually published.
Even without the vector string, the score is consistent with the described impact. Arbitrary file write that can be converted into remote code execution is typically scored near the top of the severity range because it can result in full compromise of confidentiality, integrity, and availability, depending on service privileges and platform configuration.
From a defender standpoint, the most important score interpretation is not the exact math but the exploit outcome. If an attacker can upload a crafted .st file and the service has sufficient filesystem permissions, this can become a host-level compromise path. That is especially serious in industrial or operational environments where OpenPLC may have access to control logic, plant networks, or sensitive engineering workflows.
The missing vector should not delay action. In the absence of the detailed breakdown, assume the score reflects a low-friction exploitation path with high impact and prioritize exposure reduction accordingly.
Exploitation Status
As of the provided research context, CISA KEV does not list CVE-2026-71268. That means there is no CISA-confirmed evidence of exploitation in the wild from the KEV catalog at this time. It does not mean no exploitation exists; it only means there is no KEV-backed confirmation.
For public proof-of-concept status, no dedicated PoC repository or primary-source exploit release was identified in the supplied material. However, the NVD description itself includes a concrete exploitation pattern showing how a crafted (*FILE:path content*) directive can write to /etc/cron.d/.... That is not the same as a polished exploit toolkit, but it is enough for a capable attacker to reproduce the bug with little guesswork.
Practically, defenders should treat this as highly reproducible even without a public PoC repository. The preconditions are straightforward: access to the program upload workflow, a vulnerable OpenPLC Runtime v3 instance, and process permissions that allow writing to useful target paths. If default credentials remain enabled, the attack path becomes much more realistic.
How to Detect It
Detection should focus on three areas: suspicious Structured Text uploads, unexpected filesystem writes by the OpenPLC process, and follow-on execution artifacts such as cron entries or SSH key modifications.
At the application layer, review upload activity for .st files containing the (*FILE: directive, especially where the path component includes traversal markers such as ../, absolute paths, or references to sensitive directories. Since the documented vulnerability depends on these directives being parsed and honored, those strings are strong hunting candidates.
At the host layer, monitor for OpenPLC-related processes writing outside expected application directories. If the service account suddenly creates files in /etc/cron.d/, /root/.ssh/, /home/*/.ssh/, /var/spool/cron/, or other persistence locations, treat that as high severity. Because OpenPLC is supposed to manage PLC logic, writes into system scheduling or authentication paths are anomalous.
Technical Notes
A simple content-grep approach for suspicious uploads or stored source files:
grep -RInE '\(\*FILE:|(/\.\./)+|/etc/cron\.d|authorized_keys' /path/to/openplc /var/log 2>/dev/null
Example detection pattern for web or application logs where uploaded source is logged or proxied:
(*FILE:../../../etc/cron.d/
(*FILE:../../
(*FILE:/root/.ssh/authorized_keys
(*FILE:/home/
Example Sigma-like process/file hunting logic to adapt in EDR or SIEM:
title: OpenPLC suspicious file write outside application directory
logsource:
product: linux
detection:
selection_proc:
Image|contains:
- "openplc"
- "python"
selection_target:
TargetFilename|contains:
- "/etc/cron.d/"
- "/var/spool/cron/"
- "/.ssh/authorized_keys"
condition: selection_proc and selection_target
level: high
Example shell audit search if auditd or EDR file telemetry is available:
ausearch -f /etc/cron.d -i | grep -i openplc
ausearch -f /root/.ssh/authorized_keys -i | grep -i openplc
If you lack direct application logs, prioritize filesystem and process telemetry. In many incidents, the artifact that survives longest is not the original malicious upload but the unauthorized file written to a persistence location.
Mitigation and Patching
The most important fact here is that no confirmed fixed version was identified in the cited primary sources. Because of that, it would be wrong to name a fixed release number. Defenders should assume there may be no upstream patch currently available for the referenced OpenPLC Runtime v3 code line, especially given the archived repository status.
In the absence of a verified fixed version, the safest immediate mitigation is to reduce or eliminate exposure of the vulnerable workflow. Restrict access to the OpenPLC web interface and any upload functionality to a tightly controlled management network. If default credentials are present, rotate them immediately. If the service is internet-reachable or broadly reachable from enterprise networks, isolate it now.
You should also harden filesystem permissions for the OpenPLC service account so it cannot write to sensitive OS-managed locations. Even if the application bug remains present, preventing writes to cron directories, SSH key paths, and other startup or persistence locations can block common RCE chains. Where feasible, place the service in a container, chroot, or mandatory access control profile that only permits writes to a narrow application data directory.
If you maintain the code locally, the required remediation pattern is clear from the root cause: canonicalize the destination path and reject writes that resolve outside the intended base directory. Reusing the existing validate_file_path() helper may help, but defenders should verify behavior rather than assume it is sufficient.
Technical Notes
Immediate credential and exposure reduction steps may include:
# Example: rotate default credentials in your deployment process immediately
# Exact command depends on your authentication backend; if no CLI exists,
# change credentials through the admin interface and remove defaults from automation.
Network restriction example with ufw to allow only a management subnet:
sudo ufw deny 8080/tcp
sudo ufw allow from 192.0.2.0/24 to any port 8080 proto tcp
sudo ufw reload
Example iptables restriction:
sudo iptables -A INPUT -p tcp --dport 8080 ! -s 192.0.2.0/24 -j DROP
If you must apply a local source workaround, the defensive logic should resemble:
import os
base = os.path.realpath("./core")
candidate = os.path.realpath(os.path.join(base, file_path))
if not candidate.startswith(base + os.sep):
raise ValueError("invalid file path")
If OpenPLC is run under systemd, pair the application with tighter service confinement where possible:
[Service]
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/opt/openplc/core
NoNewPrivileges=true
PrivateTmp=true
After any mitigation, retest by attempting a benign upload containing traversal sequences and confirming the application rejects it and no file is created outside the allowed directory.
References
The authoritative public reference for the vulnerability details is the NVD entry for CVE-2026-71268. That record provides the core description, affected product naming, severity, and the specific vulnerable code path in webserver/openplc.py.
The CISA Known Exploited Vulnerabilities catalog is the best source for whether US government-tracked active exploitation has been confirmed. At the time reflected in the research note, this CVE is not listed there. The OpenPLC Runtime v3 repository and referenced source file are useful for code review and local validation, though they are not a formal vendor advisory.
- NVD CVE record: https://nvd.nist.gov/vuln/detail/CVE-2026-71268
- CISA KEV catalog: https://www.cisa.gov/known-exploited-vulnerabilities-catalog
- OpenPLC Runtime v3 repository: https://github.com/thiagoralves/OpenPLC_v3
- Referenced vulnerable file: https://github.com/thiagoralves/OpenPLC_v3/blob/master/webserver/openplc.py
- Additional product/vendor aggregation: https://app.opencve.io/cve?product=openplc_v3&vendor=openplcproject
For further reading on ransomware response, check our Ransomware Response Checklist and to understand more about DNS vulnerabilities, visit our article on What is DNS Spoofing?.
If additional vendor guidance or a fixed version is published later, update internal advisories promptly. Until then, the right defensive assumption is simple: any OpenPLC Runtime v3 instance with reachable upload functionality should be treated as potentially exploitable.
This article may contain affiliate links. We earn a commission on qualifying purchases at no extra cost to you.