VYPR
High severity7.7GHSA Advisory· Published May 26, 2026· Updated May 26, 2026

FUXA has an unauthenticated arbitrary tag value disclosure via /api/getTagValue

CVE-2026-43946

Description

Summary

An authorization bypass in the /api/getTagValue endpoint allows unauthenticated access to tag values when the referenced script does not exist.

Details

The issue is caused by the combination of these code paths:

- server/api/apikeys/verify-api-or-token.js:45 sends requests without x-api-key to authJwt.verifyToken(req, res, next). - server/api/jwt-helper.js:46-64 creates a signed guest token when no x-access-token is provided: if (!token) { token = getGuestToken(); } and then populates req.userId / req.userGroups from that guest token. - server/api/command/index.js:76-105 exposes /api/getTagValue. - server/runtime/scripts/index.js:106-111 returns true when the referenced script does not exist: if (!script) { return true; }

As a result, an unauthenticated request reaches /api/getTagValue as guest, and the authorization check is bypassed because isAuthorisedByScriptName() returns true when sourceScriptName is omitted or does not match a real script. The endpoint then returns arbitrary tag values by ID.

PoC

Requests to /api/getTagValue without authentication could succeed when the authorization logic evaluated a non-existent sourceScriptName as authorized.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

An unauthenticated attacker can bypass authorization in FUXA's /api/getTagValue endpoint to read arbitrary tag values by providing a non-existent script name.

Vulnerability

The /api/getTagValue endpoint in FUXA versions prior to v1.3.1 contains an authorization bypass vulnerability. The root cause lies in server/runtime/scripts/index.js:106-111, where isAuthorisedByScriptName() returns true when the referenced script does not exist. Combined with the guest token creation logic in server/api/jwt-helper.js:46-64 (which generates a signed guest token when no x-access-token is present) and the API key verification in server/api/apikeys/verify-api-or-token.js:45 (which forwards requests without x-api-key to authJwt.verifyToken), an unauthenticated request reaches the endpoint as a guest user with bypassed authorization. An attacker can omit or supply a non-existent sourceScriptName parameter to trigger the flawed authorization check and retrieve arbitrary tag values by ID [1][2][3][4].

Exploitation

The attacker needs no authentication, no prior access, and no user interaction. A crafted HTTP GET request to /api/getTagValue with a sourceScriptName parameter that does not match any existing script (or omitting the parameter entirely) causes isAuthorisedByScriptName() to return true. The endpoint then returns the tag values requested via the id parameter. The request can be made from any network position accessible to the FUXA server, and no special headers are required [2][4].

Impact

Successful exploitation allows an unauthenticated attacker to read arbitrary tag values from the FUXA system. These tags often represent real-time industrial process data (e.g., sensor readings, control signals). Disclosure of such data can reveal sensitive operational parameters and potentially enable further reconnaissance or attacks against the ICS/SCADA environment. The compromise is limited to information disclosure (confidentiality) and does not directly enable write access or remote code execution [1][4].

Mitigation

FUXA version v1.3.1, released on or around 2026-05-26, fixes the vulnerability in commit 78534da. The fix changes the return value of isAuthorisedByScriptName() from true to false when the script does not exist, and also tightens request routing to prevent guest access to unauthorized endpoints [2][3]. Users should upgrade to v1.3.1 or later immediately. No workarounds are documented; blocking network access to the /api/getTagValue endpoint at a reverse proxy may reduce risk if immediate upgrade is not possible. This CVE is not listed on CISA's Known Exploited Vulnerabilities (KEV) catalog as of the publication date.

AI Insight generated on May 26, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected products

1

Patches

1
78534da61a91

Security fixes (#2260)

https://github.com/frangoteam/fuxaUmberto NocelliMar 19, 2026via ghsa-ref
3 files changed · +7 8
  • server/api/command/index.js+1 1 modified
    @@ -78,7 +78,7 @@ module.exports = {
                 if (res.statusCode === 403) {
                     runtime.logger.error("api get getTagValue: Tocken Expired");
                 } else if (!authJwt.haveAdminPermission(permission) && !runtime.scriptsMgr.isAuthorisedByScriptName(req.query.sourceScriptName, permission)) {
    -                res.status(400).json({error:"unauthorized_error", message: "Unauthorized!"});
    +                res.status(401).json({error:"unauthorized_error", message: "Unauthorized!"});
                     runtime.logger.error("api get getTagValue: Unauthorized");
                 } else {
                     try {
    
  • server/integrations/node-red/index.js+4 5 modified
    @@ -152,12 +152,11 @@ async function mountNodeRedIfInstalled({ app, server, settings, runtime, logger,
             });
         };
     
    -    // Allow public dashboard UI and socket.io; require JWT or API key for admin/editor/flows when security is enabled
    +    // Allow only dashboard routes as public; require JWT or API key for admin/editor/flows when security is enabled
         const allowDashboard = (req, res, next) => {
    -        const url = req.originalUrl || req.url || req.path;
    -
    -        // Public dashboard UI and its HTTP APIs (served from httpNodeRoot/ui.path)
    -        if (url.includes('/dashboard') || url.includes('/socket.io')) return next();
    +        // Public dashboard UI and its HTTP APIs (served from httpNodeRoot/ui.path).
    +        // baseUrl comes from Express mount point and is not affected by query/path tricks.
    +        if (req.baseUrl === '/dashboard') return next();
     
             if (!settings.secureEnabled || settings.nodeRedAuthMode === 'legacy-open') {
                 return next();
    
  • server/runtime/scripts/index.js+2 2 modified
    @@ -106,7 +106,7 @@ function ScriptsManager(_runtime) {
         this.isAuthorisedByScriptName = function (scriptName, permission) {
             const script = scriptModule.getScriptByName(scriptName);
             if (!script) {
    -            return true;
    +            return false;
             }
             return this.isAuthorised(script, permission);
         }
    @@ -366,4 +366,4 @@ const ScriptSchedulingMode = {
     const SchedulerType = {
         weekly: 0,
         date: 1,
    -}
    \ No newline at end of file
    +}
    

Vulnerability mechanics

Root cause

"Missing input validation in `isAuthorisedByScriptName()` returns `true` when the referenced script does not exist, allowing unauthenticated guest users to bypass authorization checks on `/api/getTagValue`."

Attack vector

An attacker sends a request to `/api/getTagValue` without any authentication headers (`x-api-key` or `x-access-token`). The request is passed through to `authJwt.verifyToken`, which creates a signed guest token and populates `req.userId`/`req.userGroups` from that guest token [ref_id=2][ref_id=3]. The endpoint then calls `isAuthorisedByScriptName(req.query.sourceScriptName, permission)`. If `sourceScriptName` is omitted or references a non-existent script, the function returns `true` (the authorization bypass), and the endpoint returns arbitrary tag values by ID [ref_id=2][ref_id=3].

Affected code

The vulnerability spans three files. In `server/runtime/scripts/index.js:106-111`, `isAuthorisedByScriptName()` returns `true` when the script is not found (`if (!script) { return true; }`). In `server/api/command/index.js:76-105`, the `/api/getTagValue` endpoint calls this function with `req.query.sourceScriptName`. In `server/api/jwt-helper.js:46-64`, a guest token is automatically created when no `x-access-token` is provided, so unauthenticated requests reach the endpoint as `guest` [ref_id=2][ref_id=3].

What the fix does

The patch makes two key changes [patch_id=2594514]. In `server/runtime/scripts/index.js`, the return value when a script is not found is flipped from `true` to `false`, so a non-existent `sourceScriptName` no longer bypasses authorization. In `server/api/command/index.js`, the HTTP status code for the unauthorized response is changed from `400` to `401`, correctly signaling an authentication/authorization failure rather than a malformed request. Additionally, the Node-RED integration's `allowDashboard` function is hardened by switching from `url.includes('/dashboard')` to `req.baseUrl === '/dashboard'` to prevent path-trickery bypasses [patch_id=2594514][ref_id=1].

Preconditions

  • authNo authentication headers (x-api-key or x-access-token) are required; the server automatically assigns a guest token
  • inputThe attacker must know or guess a valid tag ID to query via the /api/getTagValue endpoint
  • networkThe endpoint must be reachable over the network (default configuration)

Generated on May 26, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

5

News mentions

0

No linked articles in our index yet.