FUXA SCADA vulnerability RCE: bypassing Secure Mode through path confusion

Depov

Moderator
Staff member
MODERATOR
ULTIMATE
SUPREME
PREMIUM
MEMBER
Joined
Feb 18, 2025
Messages
242
Reaction score
305
Deposit
0$
The FUXA platform behind these identifiers is open-source SCADA/HMI on Node.js, which is typically raised by one team docker run -d -p 1881:1881 frangoteam/fuxa:latest and forget. Secure Mode, the only built-in FUXA authentication mechanism to protect API engrades, turned out to be so leaky that each patch gave birth to a new round vector. Below is the analysis of three classes of pre-auth RCE: from Referer spoofing through path traversal to path confusion with query string, which works even with the Node-RED authentication included.
Business logic of attack: why control HMI in the OT
FUXA is not a corporate SCADA level of Siemens WinCC or Ignition. It is a lightweight web-based visualization and management interface that is loved in small industrial projects, IoT-stands and training laboratories. Architecturally, FUXA works as a gateway between the operator and the controllers: it receives MQTT messages from PLC, exchanges data on the Modbus RTU/TCP and OPC UA, stores historical tag values in SQLite or InfluxDB.

Control over the FUXA-server gives the attacker three vectors of influence:

Manipulation of PLC tags. FUXA allows you to record values in the Holding Registers by Modbus (2016 - Write Single Register, FC 16 - Write Multiple Registers) and manage Coils (FC 05, FC 15) directly from the web interface. Through MQTT the picture is the same: recording values 1 the Topic /devices/buzzer/controls/enabled/on Includes a physical device on the controller. After compromising HMI, the attacker receives a mapping tags to registers - he knows which register is responsible for the temperature, speed or condition of the valve.

Leakage of the OT configuration. CVE-2026-25751 (CVSS 9.1, Critical, CWE-306 + CWE-312) allows you to take in InfluxDB without authentication and OPC UA connections settings through GET /api/settings.

Brew in the industrial network. In practice, FUXA is often deployed on the same host or VLAN as the PLC. Compromised through port 1881 is the starting point for the lateral movement in the OT segment.
FUXA is built on Express.js and listens to the port of 1881 by default. The project is actively developing - at the time of publication, the last release 1.3.3 is available in the npm-mesh (package @frangoteam/fuxaAccording to Snyk, patches for the CVE described below are released in versions 1.2.10, 1.2.11 and 1.3.2.

Authentication is implemented through the flag runtime.settings.secureEnabled, which activates the JWT-check in middleware secureFnc (File server/api/jwt-helper.js) When Secure Mode secureFnc is enabled, it is necessary to check every request for secure endpoints.
Foundation defects: hardcoded secret and heartbeat bypass
In addition to the non-consistent use of middleware, the foundation has two more system weaknesses:

Hardcoded JWT secret (CVE-2026-25894, CVSS 9.5 Critical via CVSS 4.0, CWE-321 + CWE-1188): if the administrator has not set a custom secret, a chircuton fallback is used. The attacker generates a valid JWT-token with administrator rights without knowing the password. Fixed at 1.2.10.

One GET request is full of rights. Fixed at 1.2.10.

In practice, Secure Mode FUXA to version 1.2.10 is a declaration, not protection. But after 1.2.10, the situation did not become fundamentally better.
Three classes of pre-auth RCE in FUXA SCADA
CVE-2025-69985: bypass JWT through the Referer header
[Applicable: external and internal pentest, FUXA <= 1.2.8]

CVSS 3.1: 9.8 Critical (AV:N/C/C/C/A:::::::H/A:H/H/A:H)
CWE: CWE-288 (Authentication Bypass Using an Alternate Path or Channel)
EPSS: 0.0563, percentage 0.92 (Top 10%) - high exposure probability
Package: @frangoteam/fuxa, last_affected 1.2.8 (according to OSV.dev)

Middleware jwt-helper.js checks the HTTP header Referr: if it contains the address of the server itself, the request is considered "inner" and is passed without JWT-check. The attacker adds Referer: http://target:1881/fuxa the POST-request for /api/runscript - and middleware lets it down. That's easy.

Endpoint /api/runscript adopts an arbitrary JavaScript code and executes it through child_process.execSync in the context of the FUXA process. Public PoC (EDB-52544, author Joshua van der Poll) demonstrates a complete grip with the output of stdout - it is enough to convey the headline Referer and JSON-body with a field script.code.

When it does not work: FUXA >= 1.2.9. In 1.2.9 Referr-extract was deleted. But in parallel, new vectors were found.
CVE-2026-25895: pre-auth path traversal via /api/upload
[Applicable: external and internal pentest, FUXA <= 1.2.9]

CVSS 4.0: 9.5 Critical (AV:N/AC:L/AT/AT/PR:N/UI:H/V:H/V:H/SI:H/SI:H/SA:H/SA:H)
CWE: CWE-22 (Path Traversal) + CWE-306 (Missing Authentication for Critical Function)
EPSS: 0.0267, Percentage 0.84 - above the median
Package: fuxa-server, fixed 1.2.10 (according to OSV.dev)

Endpoint POST /api/upload registered completely without middleware (EDB-52568, author of Anthony Cihan). Inside the processor JSON-field destination Concatenetized with appDir through path.resolve():
JavaScript:
let destinationDir = path.resolve(
runtime.settings.appDir, `_${destination}`);// destination = "a/../../../../etc/cron.d"// path.resolve()filePath = path.join(destinationDir, fileName);
fs.writeFileSync(filePath, basedata, encoding);
To the field destination Only a symbol is added _ as a prefix - no normalization and inspection of the containment. Payload Type a/../../../../<ЦЕЛЕВАЯ_ДИРЕКТОРИЯ> makes path.resolve() go beyond the appDir and write the file anywhere on the file system.

With file.type != 'svg' data is decoded from Base64, with file.type == 'svg' - written as it is (raw text). Field fullPath and fileName Filter sequences .., therefore, path traversal controls only the destination directory, but not the attachment of the file name.
GHSA-p69w-mmfv-xrfj: path via ventry string
[Applicable: external and internal pentest, FUXA 1.3.0 with Node-RED included]

Severity: High (according to the GHSA-p69w-mmffj; CVE-ID, not assigned to NVD at the time of writing)
CWE: CWE-290 (Authentication Bypass by Spoofing) - according to the classification of similar CVE in FUXA

This FUXA SCADA vulnerability RCE is interesting because it bypasses Secure Mode even with the same switched on secureEnabled and nodeRedAuthMode. Appeared in the code after the patches for CVE-2025-69985. Note: CVE-2026-25938 (CWE-290 + CWE-306, CVSS 9.5, version 1.2.8–1.2.10) describes a similar vector - auth bypass with the Node-RED included. GHSA-p69w-mmfv-xrfj may be bound or a retroactive vulnerability of the same class in later versions; the exact ratio between them requires clarification from the maintainer data.

According to advisory, auth middleware determines the need to check through substring-match on a full query URL:
JavaScript:
const url = req.originalUrl || req.url || req.path;if (url.includes('/socket.io')) return next(); req.path вместо req.originalUrlconst pathname = req.path;if (pathname.startsWith('/socket.io/')) return next();
req.originalUrl Express contains a complete URL including query string. Request GET /nodered/admin?x=/socket.io Passed the test url.includes('/socket.io') - the condition is true, middleware causes next() without JWT-check. The attacker gets access to the administrative endpoints of Node-RED. If there are branches of nodes with the ability to execute commands (exec-noda, function-noda with child_process), it's RCE.

Two points in correction: (1) req.path Instead of req.originalUrl - Express pre-parsite path, removing query string; (2) startsWith Instead of includes - other URL of the type /admin/socket.io I'd have been checked too.

When it does not work: without the included Node-RED plugin. Without him, the endpoint /nodered/* There is no way to use. According to the advisory, vulnerability is relevant for configurations, where Node-RED is used to automate the logic of management – a typical scenario for industrial IoT projects.
CVE-2026-25939 (CWE-862, Missing Authorization) is worth highlighting separately: EPSS score 0.1205, percentile ~95.6 (Top 5% by probability of operation) - the highest figure among all FUXA CVE. The attacker without authentication creates arbitrary planners who perform actions in the context of FUXA. In the OT environment, this allows you to plan a periodic re-registration of PLC tags - in fact, the persistence mechanism built into the legitimate functions of SCADA.

CVE-2026-13207 (CWE-290, CVSS 8.7, High) shows that the problem is not limited to the old versions. The vulnerability affects FUXA < = 1.3.1 after the series of patches 1.2.10 and 1.2.11. API router does not normalize dot-segment sequence before using middleware: request GET /api/./users or GET /api/project/../users returns user data and roles without authentication. CISA releases ICSA-26-181-02 for this vulnerability, evaluating Technical Impact as partial and Automatable as yes. Fixed in version 1.3.2.
 
Top Bottom