HexBrain

Browse / CVEs / CVE-2026-25895

CVE-2026-25895· frangoteam / fuxa· CWE-22

FUXA <= 1.2.9 - Unauthenticated Path Traversal to Arbitrary File Write

criticalseverity
9.8CVSS score
12.9%likelihood of exploitation, next 30 days
96%of all CVEs are less likely
Readycheck to confirm it

FUXA, an open-source Node.js SCADA/HMI web interface, through version 1.2.9 exposes an unauthenticated POST /api/upload endpoint that resolves the attacker-controlled `destination` field from the JSON request body against the application directory with only a leading underscore prefix and no containment check. Because path.resolve() honours "../" segments, an unauthenticated attacker can escape the application directory and write arbitrary files anywhere on the filesystem reachable by the service account - for example into the public web root (a/../../client/dist), into cron directories, or over SSH authorized_keys - leading to remote code execution. Version 1.2.10 rejects any destination containing a traversal segment and additionally requires an authenticated administrator.

Impact

Unauthenticated attackers can write arbitrary files anywhere on the filesystem reachable by the service account, including the public web root, cron directories, and SSH authorized_keys, leading to full remote code execution on the host running FUXA.

Fix

Upgrade FUXA to version 1.2.10 or later, which validates and contains the `destination` parameter to the intended application directory and requires administrator authentication on /api/upload.

How to confirm it

Send: POST /api/upload
Positive when: status_code == 400 and contains(body, "ENOTDIR") and contains(body, concat("main.js", "/", "{{filename}}.txt")) AND not contains "invalid_destination"

Run it with nuclei: nuclei -id CVE-2026-25895 -u <target>

The full check
id: CVE-2026-25895

info:
  name: FUXA <= 1.2.9 - Unauthenticated Path Traversal to Arbitrary File Write
  author: prithvee07
  severity: critical
  description: |
    FUXA, an open-source Node.js SCADA/HMI web interface, through version 1.2.9 exposes an unauthenticated POST /api/upload endpoint that resolves the attacker-controlled `destination` field from the JSON request body against the application directory with only a leading underscore prefix and no containment check. Because path.resolve() honours "../" segments, an unauthenticated attacker can escape the application directory and write arbitrary files anywhere on the filesystem reachable by the service account - for example into the public web root (a/../../client/dist), into cron directories, or over SSH authorized_keys - leading to remote code execution. Version 1.2.10 rejects any destination containing a traversal segment and additionally requires an authenticated administrator.
  impact: |
    Unauthenticated attackers can write arbitrary files anywhere on the filesystem reachable by the service account, including the public web root, cron directories, and SSH authorized_keys, leading to full remote code execution on the host running FUXA.
  remediation: |
    Upgrade FUXA to version 1.2.10 or later, which validates and contains the `destination` parameter to the intended application directory and requires administrator authentication on /api/upload.
  reference:
    - https://github.com/frangoteam/FUXA/security/advisories/GHSA-88qh-cphv-996c
    - https://github.com/frangoteam/FUXA/commit/22c2192f5d9beef8a787c45eff3a14c24dbb5f96
    - https://github.com/frangoteam/FUXA/releases/tag/v1.2.10
    - https://github.com/Hann1bl3L3ct3r/FUXAPWN
    - https://nvd.nist.gov/vuln/detail/CVE-2026-25895
  classification:
    cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
    cvss-score: 9.8
    cve-id: CVE-2026-25895
    epss-score: 0.1285
    epss-percentile: 0.96329
    cwe-id: CWE-22
  metadata:
    verified: true
    max-request: 1
    vendor: frangoteam
    product: fuxa
    shodan-query: http.title:"FUXA"
    fofa-query: title="FUXA"
  tags: cve,cve2026,fuxa,scada,path-traversal,file-upload,rce,unauth,vkev

variables:
  filename: "{{rand_base(10,'abcdefghijklmnopqrstuvwxyz')}}"

http:
  - raw:
      - |
        POST /api/upload HTTP/1.1
        Host: {{Hostname}}
        Content-Type: application/json

        {"resource":{"name":"{{filename}}.txt","fullPath":"{{filename}}.txt","type":"bin","data":"{{base64(filename)}}"},"destination":"a/../../server/main.js"}

    matchers-condition: and
    matchers:
      - type: dsl
        dsl:
          - 'status_code == 400'
          - 'contains(body, "ENOTDIR")'
          - 'contains(body, concat("main.js", "/", "{{filename}}.txt"))'
        condition: and

      - type: word
        part: body
        words:
          - "invalid_destination"
        negative: true

    extractors:
      - type: regex
        part: body
        group: 1
        regex:
          - "open '(.*?)'"

References

Use this check only on systems you are authorised to test. Where the data comes from