GHSA-VWCG-C828-9822

FUXA: From Heartbeat to Flatline – Unauthenticated RCE via JWT Minting

Alon Barad
Alon Barad
Software Engineer

Feb 5, 2026·6 min read·0 visits

Executive Summary (TL;DR)

FUXA versions <= 1.2.9 contain a critical flaw in the `/api/heartbeat` endpoint where the server blindly trusts the `x-auth-user` header. Attackers can inject a JSON payload claiming to be an admin, and the server will sign it with its private key, returning a valid administrative JWT. This grants full control over the SCADA system, enabling RCE.

A critical authentication bypass in the FUXA SCADA visualization software allows unauthenticated attackers to mint arbitrary administrative JWTs by simply asking nicely via HTTP headers. This flaw leads to full Remote Code Execution (RCE) on the host server.

The Hook: Trust Issues in Industrial IoT

In the world of SCADA and HMI (Human-Machine Interface) software, security is often treated like a garnish rather than a main ingredient. FUXA, a popular open-source web-based process visualization tool, allows users to monitor sensors, control PLCs, and build dashboards. It sits right at the intersection of "Web Application" and "Critical Infrastructure," which is usually where the nightmares begin.

This particular vulnerability isn't some complex heap overflow or a race condition requiring microsecond precision. It represents the cardinal sin of web development: blindly trusting client input. Imagine walking into a high-security bank vault, handing the guard a sticky note that says "I am the CEO," and having him immediately hand you the keys to the safe. That is exactly what FUXA was doing.

The flaw resides in the application's "heartbeat" mechanism—a pulse check designed to keep sessions alive. Unfortunately, this heartbeat didn't just check for life; it offered resurrection. By exploiting this endpoint, an attacker requires zero credentials to elevate themselves from "anonymous internet rando" to "system administrator," gaining the power to modify industrial processes and execute arbitrary code on the server.

The Flaw: A Header to Rule Them All

The root cause is a staggering misunderstanding of where truth resides in a client-server architecture. In a secure implementation, a session refresh logic should look at the existing valid session (the cookie or the current JWT), verify its signature, and then issue a new token based on the server's knowledge of that user.

FUXA, however, took a shortcut. In server/api/jwt-helper.js, the function responsible for minting new tokens during a heartbeat request didn't look at the server's session store or verify the incoming token's signature first. Instead, it looked at an HTTP header: x-auth-user.

Here is the logic flaw in plain English: The server essentially said, "If you want a new token, just tell me who you are in the x-auth-user header, and I'll sign a fresh JWT for you using my private secret." The code failed to realize that HTTP headers are entirely user-controlled. There was no validation that the request came from an already authenticated user. The gatekeeper was asleep, and the key printing machine was left in the lobby.

The Code: The Smoking Gun

Let's dissect the vulnerable code in server/api/jwt-helper.js. The vulnerability existed because the token generation logic was decoupled from authentication verification.

The Vulnerable Code:

// PRE-PATCH logic
function getNewToken(headers) {
    if (headers && headers['x-auth-user']) {
        // DANGER: Parsing user identity directly from client headers
        var user = JSON.parse(headers['x-auth-user']);
        // The server signs whatever is in 'user' with its private secret
        return jwt.sign(user, secretCode, { expiresIn: tokenExpires });
    }
    return null;
}

As you can see, JSON.parse takes the raw string from the header, and jwt.sign cryptographically signs it. It doesn't matter if you've never logged in; if you send the header, you get a token.

The Fix (Commit fe82348):

The patch introduces a sanity check. It ensures the request is actually authenticated before even thinking about issuing a new token. It also stops reading from the header entirely, pulling user data from the req object which is populated by middleware only after a valid token signature check.

// PATCHED logic
function getNewTokenFromRequest(req) {
    // 1. Verify the user is actually authenticated
    if (!req.isAuthenticated) return null;
    
    // 2. Use the verified identity from the request context, not headers
    var user = {
        user: req.userId,
        groups: req.userGroups
    };
    return jwt.sign(user, secretCode, { expiresIn: tokenExpires });
}

This change shifts the "source of truth" from the attacker-controlled header back to the server-verified session context.

The Exploit: Becoming God Mode

Exploiting this is trivially easy. You don't need Metasploit; you just need curl. The goal is to mint a token that gives us administrator privileges. In FUXA, the default admin group is often designated by the ID -1 or broadly scoped permissions.

Here is the attack chain:

  1. Target: The /api/heartbeat endpoint.
  2. Payload: We craft a JSON object representing the user we want to be. {"user":"admin", "groups":[-1]}.
  3. Delivery: We inject this into the x-auth-user header.

Proof of Concept:

curl -X POST http://target-ip:1881/api/heartbeat \
  -H "Content-Type: application/json" \
  -H 'x-auth-user: {"user":"admin","groups":[-1]}' \
  -d '{"params": true}'

The Result: The server replies with a 200 OK and a JSON body containing a freshly minted, cryptographically valid JWT.

Once you have this token, you add it to the Authorization header of subsequent requests. Since FUXA allows administrators to define scripts and server-side actions (a feature of SCADA HMI logic), you can now navigate to the script editor, write a Node.js script to spawn a reverse shell, and execute it. You have effectively turned the dashboard into a command and control server.

The Impact: Why This Matters

This isn't just about defacing a website. We are talking about Industrial Control Systems (ICS). FUXA is designed to visualize and control machinery, sensors, and production lines.

The Nightmare Scenario:

  1. Physical Damage: An attacker could override safety thresholds, turn off cooling systems, or manipulate values sent to PLCs (Programmable Logic Controllers), causing physical damage to equipment.
  2. Operational Paralysis: Deleting project files or corrupting the database stops production.
  3. Lateral Movement: The RCE on the FUXA server provides a perfect pivot point into the operational technology (OT) network, which is often air-gapped or segmented from the corporate IT network.

Furthermore, the ease of exploitation (a single HTTP request) makes this wormable. A simple script could scan the internet for FUXA instances and automatically backdoor them.

Mitigation: Stopping the Bleeding

If you are running FUXA, you need to act immediately.

1. Update Immediately Update your FUXA instance to a version that includes commit fe82348. This effectively closes the header injection hole. If you are using Docker, pull the latest image.

2. Rotate Your Secrets Even after patching, if you were using the default configuration, you might be in trouble. The source code historically contained a default secret: frangoteam751. If you haven't changed this in your settings.js or environment variables, an attacker doesn't even need the heartbeat exploit—they can just sign their own tokens offline using this known string.

3. Network Segmentation Never expose HMI/SCADA interfaces directly to the internet. Place FUXA behind a VPN or a reverse proxy with strict authentication (like Basic Auth) before the traffic even hits the FUXA application logic.

Fix Analysis (1)

Technical Appendix

CVSS Score
9.8/ 10
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H

Affected Systems

FUXA SCADA/HMI Web ServerIndustrial IoT Dashboards running FUXANode.js environments hosting FUXA <= 1.2.9

Affected Versions Detail

Product
Affected Versions
Fixed Version
FUXA
frangoteam
<= 1.2.9Commit fe82348 (Post-1.2.9)
AttributeDetail
CWE-287Improper Authentication
Attack VectorNetwork (Remote)
CVSS v3.19.8 (Critical)
Privileges RequiredNone
ImpactRemote Code Execution (RCE)
Vulnerable Component/api/heartbeat Endpoint
CWE-287
Improper Authentication

Vulnerability Timeline

Patch committed to GitHub repository
2026-01-16
Vulnerability publicly disclosed (GHSA-VWCG-C828-9822)
2026-02-04

Subscribe to updates

Get the latest CVE analysis reports delivered to your inbox.