CVE-2026-93988 Overview
CVE-2026-93988 is a path traversal vulnerability in QloApps through version 1.7.0. The flaw resides in the getEmailHTML action of admin/ajax.php. Authenticated back-office users can supply relative path sequences in the email parameter to escape the intended directory. This enables reading arbitrary files on the underlying host, including database credentials and application configuration. The weakness is classified under CWE-22: Improper Limitation of a Pathname to a Restricted Directory.
Critical Impact
Authenticated administrators can exfiltrate sensitive server-side files such as config/settings.inc.php, exposing database credentials and cryptographic secrets that enable further compromise of the QloApps deployment.
Affected Products
- QloApps versions up to and including 1.7.0
- QloApps back-office administrative interface (admin/ajax.php)
- Deployments exposing the AdminTranslationsControllergetEmailHTML action
Discovery Timeline
- 2026-09-19 - CVE-2026-93988 published to the National Vulnerability Database
- 2026-09-22 - Last updated in NVD database
Technical Details for CVE-2026-93988
Vulnerability Analysis
QloApps exposes a getEmailHTML AJAX action inside admin/ajax.php that renders email templates for the back office. The handler, implemented in controllers/admin/AdminTranslationsController.php, accepts an email parameter and uses it to build a filesystem path for reading the requested template. The path is not normalized or constrained to the intended mail template directory. An authenticated back-office user can inject ../ sequences in the email value to traverse outside the mail template root. The server then reads and returns the target file's contents in the HTTP response.
The reachable impact is confidentiality only: no integrity or availability primitives are exposed by this endpoint. However, the readable files include config/settings.inc.php, which stores database credentials and the cookie encryption key. Recovery of those secrets enables lateral abuse such as database compromise and session forgery.
Root Cause
The root cause is missing input validation and path canonicalization on the email request parameter before it is concatenated into a filesystem read. The controller trusts user-supplied input to identify a template rather than mapping it against an allowlist or resolving the final path and verifying it is contained within the mail template directory.
Attack Vector
Exploitation requires an authenticated back-office session, but no user interaction and no elevated privileges beyond a low-privileged staff account. The attacker sends a crafted request to admin/ajax.php invoking the getEmailHTML action with an email value containing traversal sequences that resolve to a target file such as ../../../config/settings.inc.php. The response body contains the file contents. Refer to the VulnCheck advisory and the HackMD analysis for the request format and reproduction steps.
Detection Methods for CVE-2026-93988
Indicators of Compromise
- Requests to admin/ajax.php where the action parameter equals getEmailHTML and the email parameter contains ../, ..\, %2e%2e%2f, or other encoded traversal sequences.
- Web server access logs showing getEmailHTML responses with unusually large payloads or Content-Type values inconsistent with rendered HTML email templates.
- Read access from the PHP-FPM or web server process to sensitive files such as config/settings.inc.php, .env, or /etc/passwd originating from the QloApps document root.
Detection Strategies
- Deploy a web application firewall rule that inspects the email parameter on admin/ajax.php for path traversal tokens and blocks or alerts on matches.
- Correlate authenticated back-office session identifiers with anomalous getEmailHTML request rates or with requests targeting non-existent template names.
- Baseline file access telemetry for the QloApps installation directory and flag reads of configuration files by the web server user outside of application startup.
Monitoring Recommendations
- Enable verbose access logging for the admin/ path and forward logs to a centralized analytics pipeline for retention and search.
- Alert on any 200-response containing _DB_PASSWD_ or _COOKIE_KEY_ strings in outbound HTTP responses from the QloApps host.
- Monitor back-office administrator accounts for suspicious login geographies or session reuse that could indicate compromised credentials being used to trigger the flaw.
How to Mitigate CVE-2026-93988
Immediate Actions Required
- Upgrade QloApps to a version that includes commit 8015495 merged via Pull Request #1719.
- Rotate database credentials, the QloApps cookie key, and any other secrets stored in config/settings.inc.php, since exploitation may have already occurred.
- Audit back-office user accounts, remove unused administrators, and enforce strong password requirements plus multi-factor authentication for staff logins.
Patch Information
The upstream fix is tracked in the QloApps GitHub repository and applied through commit 8015495ca746127920fbcde1f9507c024b26a715. The patch hardens archive and template handling paths in AdminTranslationsController.php and short-circuits processing when input validation fails. Review the following change for context:
$files_list = AdminTranslationsController::filterTranslationFiles($gz->listContent());
$files_paths = AdminTranslationsController::filesListToPaths($files_list);
+ if (empty($files_list)) {
+ $this->errors[] = Tools::displayError('No valid translation files found in the archive.');
+ return false;
+ }
+
$uniqid = uniqid();
$sandbox = _PS_CACHE_DIR_.'sandbox'.DIRECTORY_SEPARATOR.$uniqid.DIRECTORY_SEPARATOR;
- if ($gz->extractList($files_paths, $sandbox)) {
- foreach ($files_list as $file2check) {
- //don't validate index.php, will be overwrite when extract in translation directory
- if (pathinfo($file2check['filename'], PATHINFO_BASENAME) == 'index.php') {
- continue;
- }
+ if (!$gz->extractList($files_paths, $sandbox)) {
+ $this->errors[] = Tools::displayError('The archive cannot be extracted.');
+ Tools::deleteDirectory($sandbox, true);
+ return false;
+ }
+ foreach ($files_list as $file2check) {
+ //don't validate index.php, will be overwrite when extract in translation directory
Source: QloApps commit 8015495
Workarounds
- Restrict network access to the admin/ path with IP allowlisting or a VPN until the patch is deployed.
- Add a web server rewrite rule that rejects requests to admin/ajax.php when the email parameter contains .., %2e%2e, or backslash sequences.
- Run the web server process under a least-privilege account and use filesystem ACLs to deny read access to config/settings.inc.php from arbitrary paths outside the application bootstrap.
# Example NGINX guard for the getEmailHTML action
location = /admin/ajax.php {
if ($arg_action = "getEmailHTML") {
if ($args ~* "(\.\./|\.\.\\|%2e%2e)") {
return 403;
}
}
include fastcgi_params;
fastcgi_pass unix:/run/php/php-fpm.sock;
}
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.
