CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



CVE-2026-25951
8.6

FUXA Faux Pas: From Weak Regex to SCADA RCE

Amit Schendel
Amit Schendel
Senior Security Researcher

Feb 10, 2026·6 min read·19 visits

PoC Available

Executive Summary (TL;DR)

FUXA tried to stop directory traversal by deleting '../' strings, but they only did it once. By sending '....//', attackers can bypass the filter, write a malicious JavaScript file to the auto-loading 'runtime/scripts' folder, and achieve immediate RCE on the SCADA server.

A critical path traversal vulnerability in the FUXA SCADA/HMI web interface allows authenticated administrators to escape the filesystem sandbox using nested directory sequences. Because FUXA dynamically reloads scripts found in its runtime directory, this filesystem write primitive automatically escalates to Remote Code Execution (RCE), potentially giving attackers control over industrial control systems.

The Hook: SCADA on the Web, What Could Go Wrong?

In the world of Industrial Control Systems (ICS), the line between "air-gapped safe haven" and "accessible web interface" is blurring faster than a centrifuge spinning out of control. Enter FUXA, a modern, open-source SCADA (Supervisory Control and Data Acquisition) and HMI (Human-Machine Interface) solution. It’s built with Node.js, uses WebSockets, and offers a slick interface for managing PLCs (Programmable Logic Controllers). It’s the kind of tool that makes an OT (Operational Technology) engineer's life easier and a security researcher's heart race.

Here is the reality of modern SCADA: we are moving away from proprietary, binary protocols and toward standard web technologies. While this improves interoperability, it also imports the entire history of web vulnerabilities into the factory floor. FUXA allows administrators to upload project files, manage resources, and script logic. It’s a powerful feature set.

But power requires control. CVE-2026-25951 is a classic example of what happens when a developer tries to implement security controls manually rather than using established libraries. It’s a vulnerability that transforms a simple file management feature into a weapon that can override industrial processes.

The Flaw: The Curse of the Single Pass

The root cause of this vulnerability is a lesson taught in every 'Intro to AppSec' class: Do not implement your own sanitization using simple string replacement. The developers of FUXA wanted to prevent users from accessing files outside of the intended directory. They knew that ../ is the universal signal for "let me out," so they wrote a filter to destroy it.

The logic (roughly) looked like this:

// The "Security" Filter
const cleanPath = userInput.replace(new RegExp('../', 'g'), '');

This is a blacklist approach, and it suffers from a fatal logical error known as non-recursive sanitization. The regex engine sweeps through the string once. It finds every instance of ../ and deletes it. That sounds fine, until you think like a hacker.

If you provide the string ....//, the regex engine sees the ../ sitting in the middle. It deletes those three characters. What is left? The two dots at the beginning and the slash at the end merge together to form a new ../. The application then happily passes this newly formed directory traversal sequence to the filesystem APIs. It is like locking your front door but leaving a key under the mat, and writing "Key Under Mat" on the doorframe.

The Code: Anatomy of a Fix

Let's look at the actual code changes to understand the gravity of the mistake and the correctness of the solution. The patch, applied in commit f7a9f04b2ab97ab5421e4ec4e711c51e9f4b65c8, completely rips out the regex logic in favor of path canonicalization.

The Vulnerable Pattern:

// OLD: Vulnerable to nested sequences
var fileName = req.query.name.replace(/\.\.\//g, '');
fs.writeFile(path.join(baseDir, fileName), ...);

The Fix (The Jail Pattern):

The developers implemented a new utility, resolveWithin, which forces the path to be absolute and checks if it still resides within the intended directory.

// NEW: server/api/path-helper.js
function resolveWithin(baseDir, targetPath) {
    // 1. Normalize the input (removes redundant slashes, resolves '..')
    const normalized = normalizeRelativePath(targetPath);
    if (!normalized) return null;
 
    // 2. Resolve absolute paths
    const resolvedBase = path.resolve(baseDir);
    const resolvedTarget = path.resolve(resolvedBase, normalized);
 
    // 3. Calculate relative path between Base and Target
    const relative = path.relative(resolvedBase, resolvedTarget);
 
    // 4. If the relative path starts with '..', it tried to escape!
    if (relative.startsWith('..') || path.isAbsolute(relative)) {
        return null;
    }
    return { resolvedTarget, normalized };
}

This is the correct way to handle file paths. It doesn't guess what the attacker might send; it resolves the final destination and checks if that destination is legally allowed. If the math says the file is outside the jail, the request is dropped.

The Exploit: From Traversal to RCE

So we have a path traversal. Usually, this means we can read /etc/passwd or C:\Windows\win.ini. That's bad, but in FUXA's case, it's catastrophic. The system allows writing files, and critically, it monitors the runtime/scripts directory for changes.

Here is the kill chain:

  1. Recon: The attacker authenticates as an admin. This might seem like a high bar, but default credentials or phishing in OT environments are depressingly common.
  2. Payload Construction: The attacker crafts a malicious JavaScript file, pwn.js, containing a reverse shell or a command to dump database credentials.
  3. The Injection: The attacker targets an upload endpoint or a resource management endpoint using the bypass sequence.
    POST /api/resources?name=....//....//runtime/scripts/pwn.js HTTP/1.1
    ...
    [Malicious JavaScript Content]
  4. The Execution: The flawed regex strips the inner ../, leaving ../../runtime/scripts/pwn.js. The file is written to the disk.
  5. The Trigger: FUXA's backend detects a file change in the scripts directory. It automatically hot-reloads the script to apply "project updates." The attacker's code executes immediately within the context of the Node.js server process. No restart required. No waiting. Instant shell.

The Impact: Why This Matters

CVSS scores (8.6 in this case) often fail to capture the visceral reality of an OT compromise. If this were a blog engine, RCE would mean defacement. In FUXA, RCE means the attacker controls the HMI.

From the HMI, an attacker can:

  • Spoof Data: Tell the operator the reactor is 20°C when it is actually 200°C.
  • Send Commands: Trigger actuators, open valves, or shut down safety systems via the connected PLCs.
  • Lateral Movement: Use the FUXA server as a pivot point to attack the deeper, PLC-level network (Purdue Level 1).

This vulnerability bridges the gap between the IT network (where the web interface lives) and the OT network (where the physical machinery lives). It is a direct tunnel from a web browser to physical destruction.

Mitigation: Patching the Hole

The remediation is straightforward but urgent. The vulnerability is patched in FUXA version 1.2.11. If you are running an older version, you are exposed.

Immediate Steps:

  1. Update: Pull the latest docker image or update your git repository to tag v1.2.11.
  2. Network Isolation: Ensure your HMI is NOT exposed to the public internet. It should sit behind a VPN and be accessible only from a management VLAN.
  3. Audit: Check your runtime/scripts directory. If you see files you didn't put there, assume compromise and initiate incident response.

For developers reading this: this is your reminder to never trust user input, especially when it deals with filesystems. Use the standard library's path resolution tools. Regex is not a firewall.

Official Patches

frangoteamFix commit implementing resolveWithin logic

Fix Analysis (1)

Technical Appendix

CVSS Score
8.6/ 10
CVSS:4.0/AV:N/AC:L/AT:N/PR:H/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N

Affected Systems

FUXA SCADA/HMI Web Server

Affected Versions Detail

Product
Affected Versions
Fixed Version
FUXA
frangoteam
< 1.2.111.2.11
AttributeDetail
CWE IDCWE-22 (Path Traversal)
CVSS v4.08.6 (High)
Attack VectorNetwork
Privileges RequiredHigh (Admin)
ImpactRemote Code Execution (RCE)
StatusPatched (v1.2.11)

MITRE ATT&CK Mapping

T1059Command and Scripting Interpreter
Execution
T1190Exploit Public-Facing Application
Initial Access
T1203Exploitation for Client Execution
Execution
CWE-22
Path Traversal

Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')

Known Exploits & Detection

GitHub Security AdvisoryDetailed analysis of the nested traversal payload and RCE vector.

Vulnerability Timeline

CVE Published
2026-02-09
Patch v1.2.11 Released
2026-02-09

References & Sources

  • [1]GHSA Advisory
  • [2]NVD CVE-2026-25951

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.