Jul 14, 2026·7 min read·4 visits
An authenticated path traversal vulnerability in FacturaScripts allows arbitrary file uploads and server configuration overrides, resulting in unauthenticated remote code execution via public directories.
FacturaScripts is an open-source PHP-based enterprise resource planning (ERP) and billing software. A critical path traversal vulnerability in the file-handling logic allows authenticated attackers with file upload permissions to write arbitrary files to any location on the system writable by the web server user. By writing custom server configuration files (.htaccess) to directories excluded from default rewrite rules, attackers can map allowed file types (like .png) to the PHP interpreter, leading to full remote code execution.
FacturaScripts is an open-source enterprise resource planning (ERP) and billing application written in PHP. The software utilizes a custom file-handling architecture to manage document attachments, plugin updates, and system assets. Within this file management system, the UploadedFile class encapsulates uploaded file resources, determining their target destinations and enforcing security controls.
The attack surface is exposed through multiple endpoints that accept user-provided file uploads. These endpoints include the application programming interfaces (APIs) for uploading and attaching files, as well as core widgets and controller classes used for document registration and administration. The vulnerable system component is the UploadedFile::move() method, which performs the physical migration of files from PHP's temporary staging directory to persistent storage on the host filesystem.
The flaw is categorized under CWE-22 (Improper Limitation of a Pathname to a Restricted Directory) and CWE-434 (Unrestricted Upload of File with Dangerous Type). By exploiting this flaw, an authenticated user with permission to upload files can bypass intended storage boundaries. The consequence of successful exploitation is arbitrary write access to any location on the system filesystem that is writable by the running web server process, potentially leading to unauthorized execution of administrative commands.
The root cause of the vulnerability resides in the implementation of the move() method inside Core/UploadedFile.php. When processing a file migration request, the application does not perform any sanitization, normalization, or canonicalization of the destination filename retrieved via the getClientOriginalName() method. This allows client-provided input to control the target file path directly.
The system attempts to validate uploads using the isValid() method, which contains a blocklist mechanism defined by the constant BLOCKED_EXTENSIONS. This blocklist restricts specific execution extensions, such as phar, php, php3, and other PHP variants. However, this defense is fundamentally flawed because it relies on a negative security model (blocking known-bad extensions) rather than an allowlist of permitted extensions, and it fails to analyze or strip directory traversal components (such as ../) from the filename.
When a file upload request is processed, the application concatenates the absolute or relative target directory path with the client-provided name using a direct string append operation ($destiny . $destinyName). Because directory traversal sequences are not filtered or resolved, an attacker can specify a filename containing relative directory steps to escape the intended directory tree. For instance, supplying ../Dinamic/Assets/traversed.txt forces the filesystem to write outside the default /MyFiles/ namespace and place the file in the public assets directory instead.
An analysis of the vulnerable source code in Core/UploadedFile.php highlights the absence of boundary enforcement or input sanitization. The target path is directly influenced by the client parameter without verification. Below is the vulnerable implementation of the file transfer logic:
// Core/UploadedFile.php - Vulnerable Implementation
private const BLOCKED_EXTENSIONS = ['phar', 'php', 'php3', 'php4', 'php5', 'php7', 'php8', 'pht', 'phtml', 'phps'];
public function move(string $destiny, string $destinyName): bool
{
if (!$this->isValid()) {
return false;
}
if (substr($destiny, -1) !== DIRECTORY_SEPARATOR) {
$destiny .= DIRECTORY_SEPARATOR;
}
return $this->test ?
rename($this->tmp_name, $destiny . $destinyName) :
move_uploaded_file($this->tmp_name, $destiny . $destinyName);
}The vulnerability is introduced when $destinyName is appended to $destiny inside move_uploaded_file or rename. Because there is no check ensuring that the path resolved by $destiny . $destinyName remains within the root directory defined by $destiny, path traversal is achieved.
The official remediation introduces a simple sanitization step targeting the input parameter. By utilizing PHP's built-in basename() function, any leading path components or directory sequences are stripped, isolating only the trailing name component:
// Core/UploadedFile.php - Patched Implementation
public function move(string $destiny, string $destinyName): bool
{
if (!$this->isValid()) {
return false;
}
// Strip any directory components from the client-supplied filename
$destinyName = basename($destinyName);
if (substr($destiny, -1) !== DIRECTORY_SEPARATOR) {
$destiny .= DIRECTORY_SEPARATOR;
}
return $this->test ?
rename($this->tmp_name, $destiny . $destinyName) :
move_uploaded_file($this->tmp_name, $destiny . $destinyName);
}While the introduction of basename() successfully blocks basic relative traversal attempts, security teams must note that basename() behavior varies depending on the host operating system. On Windows servers, basename() recognizes both forward slashes (/) and backslashes (\) as directory separators, whereas on Linux/Unix platforms, it only recognizes forward slashes. This leaves a minor discrepancy where backslashes remain unmodified on Unix hosts, although Unix filesystems generally treat literal backslashes as part of the filename itself, preventing actual traversal exploitation.
Exploitation of this vulnerability requires authenticated access to an endpoint that supports file uploads, such as the attachment API or any controller leveraging the file widget. The attack chain leverages a multi-stage approach to bypass both extension blocklists and web server access restrictions.
The first stage of the attack takes advantage of Apache rewrite configurations distributed with FacturaScripts in its default .htaccess layout. To ensure that assets and Node modules are delivered directly without being routed through the main PHP front controller, the configuration explicitly excludes specific directories from rewrites:
RewriteCond %{REQUEST_URI} !Dinamic/Assets/ [NC]
RewriteCond %{REQUEST_URI} !node_modules/ [NC]
RewriteRule . index.php [L]Because requests targeting /Dinamic/Assets/ are handled directly by Apache, files written into this path will be processed and executed by the server engine rather than being routed through FacturaScripts. An attacker exploits this by performing two sequential uploads:
First, the attacker uploads a file with the name set to ../Dinamic/Assets/.htaccess. Since .htaccess is not in the BLOCKED_EXTENSIONS list, the application writes the file to the asset directory. The content of this file instructs Apache to treat .png files as executable PHP scripts:
AddType application/x-httpd-php .png
Second, the attacker uploads a script containing standard PHP execution payloads (such as a system command runner) named ../Dinamic/Assets/shell.png. Because .png is an allowed extension, the file bypasses all structural checks. Finally, the attacker makes a direct GET request to /Dinamic/Assets/shell.png?cmd=whoami, triggering the PHP parser and executing arbitrary commands on the system.
The security impact of this vulnerability is critical, with a CVSS v3.1 base score of 9.9. Because the vulnerability results in arbitrary file write capability inside web-accessible directories, the confidentiality, integrity, and availability of the underlying server are compromised.
Once an attacker successfully executes arbitrary commands, they gain the system permissions of the web server user (such as www-data or apache). From this position, the attacker can access sensitive configuration files containing database credentials, manipulate database tables containing financial or customer records, and pivot to adjacent resources within the corporate network.
Furthermore, because this is an ERP and billing application, access to the application database poses significant business risks, including unauthorized data modification, billing fraud, and intellectual property theft. The ability to overwrite system files also permits permanent denial of service or persistent backdoor installations, establishing long-term control over the target environment.
To eliminate the path traversal vulnerability, administrators and developers must apply both code-level corrections and host-level security policies. The primary mitigation is to apply the code patch that introduces basename() to all file destination routines inside the UploadedFile class.
In addition to applying the patch, organizations should implement defense-in-depth measures to mitigate any residual risk. First, web server configurations should be hardened to prevent the execution of dynamic scripts within user-writable directories. For Apache servers, this can be achieved by placing a global directory rule in the main server configuration that restricts file execution inside the assets folder:
<Directory "/var/www/html/Dinamic/Assets">
AllowOverride None
AddHandler default-handler .php .phtml .php3
RemoveHandler .php .phtml .php3
</Directory>Second, the application should transition from a file extension blocklist to a strict allowlist of permitted extensions. Only explicitly approved file types (such as pdf, png, and jpg) should be accepted, and all incoming files should have their MIME types verified using PHP's file information extension (finfo_file) to ensure that file extensions match their true file contents.
| Attribute | Detail |
|---|---|
| CWE ID | CWE-22, CWE-434 |
| Attack Vector | Network (AV:N) |
| CVSS v3.1 Score | 9.9 (Critical) |
| Exploit Status | Proof of Concept (PoC) documented |
| Impact | Remote Code Execution (RCE) |
A critical Denial of Service (DoS) vulnerability in the Ech0 publishing platform allows unauthenticated remote attackers to exhaust CPU resources via a crafted Accept-Language header. By utilizing underscore separators instead of hyphens, the attack bypasses the CVE-2022-32149 guard within the Go language tag parser, triggering a quadratic-time complexity operation.
Nebula-mesh allows non-admin operators to disable webhook SSRF (Server-Side Request Forgery) protection via the allow_private parameter. Low-privilege operators can configure webhook endpoints targeting internal endpoints and trigger lifecycle events on resources they own, bypassing network access controls.
An information exposure vulnerability exists in Umbraco.AI package versions up to 1.13.0, where an authenticated backoffice user with elevated privileges can resolve and retrieve arbitrary configuration values from the global ASP.NET Core IConfiguration hierarchy.
A technical analysis of CVE-2025-61670, a memory leak vulnerability in Wasmtime's C and C++ API bindings. The issue stems from a refactoring in version 37.0.0 that transitioned garbage-collected reference tracking to host heap-allocated OwnedRooted types without updating FFI ownership semantics.
A critical authentication bypass vulnerability in Woodpecker CI allows authenticated agents to impersonate other agents by injecting spoofed agent_id values into gRPC metadata. This flaw is caused by the use of md.Append instead of md.Set on the server-side RPC authorizer.
Fedify, a TypeScript framework for ActivityPub servers, implemented incomplete public URL validation inside the @fedify/fedify and @fedify/vocab-runtime libraries. The validator only blocked basic RFC 1918 networks, standard loopbacks, and link-local addresses, failing to restrict Carrier-Grade NAT (CGNAT), benchmarking, reserved, or IPv6 transition addresses. Consequently, unauthenticated remote attackers can bypass SSRF filters to access sensitive internal microservices and endpoints.