Introduction
An unauthenticated SQL injection in phpMyFAQ's public captcha API endpoint allows remote attackers to extract password hashes, admin tokens, and SMTP credentials from the underlying database using nothing more than a crafted User-Agent header. With a CVSS score of 9.8 and a publicly available proof of concept, this vulnerability represents a serious risk for any organization running phpMyFAQ versions prior to 4.1.2.
phpMyFAQ is an open source FAQ web application built for PHP 8.3+ with support for MySQL, PostgreSQL, and other database backends. Maintained by Thorsten Rinne under the MPL-2.0 license, the project has accumulated 616 stars and 263 forks on GitHub, serving organizations that need a self-hosted knowledge base solution. While not as widely deployed as commercial alternatives, phpMyFAQ fills an important niche in the open source ecosystem for teams that require full control over their FAQ infrastructure.
Technical Information
The vulnerability resides in the BuiltinCaptcha class, specifically in two methods: garbageCollector() and saveCaptcha(). Both methods construct SQL queries using sprintf() and interpolate the userAgent and ip fields directly from the incoming HTTP request. Neither field passes through Database::escape() or a prepared statement before reaching the query.
On every request to the public GET /api/captcha endpoint, the getCaptchaImage() function unconditionally calls both vulnerable methods. This creates two distinct SQL injection sinks per request:
- A
DELETEquery ingarbageCollector() - An
INSERTquery insaveCaptcha()
The endpoint requires no authentication, no CSRF token, no session, and enforces no rate limiting. Any remote attacker can reach both sinks by simply issuing a GET request with a malicious User-Agent header.
Exploitation Flow
MySQL's query() method executes only one statement per call, which prevents query stacking. However, time-based blind SQL injection remains fully effective. An attacker injects SQL functions such as SLEEP() or BENCHMARK() into the User-Agent header value.
The dual sink nature of the vulnerability provides a clear confirmation signal. A baseline request to the captcha endpoint completes in approximately 0.147 seconds. When the User-Agent header contains a payload like x' OR SLEEP(2) OR 'x, the response takes approximately 4.093 seconds. The four-second delay (rather than two) confirms that the SLEEP(2) command executes twice: once in the DELETE statement and once in the INSERT statement.
From there, attackers use single-bit boolean extraction techniques to iterate through database rows and exfiltrate sensitive data. The primary targets are:
- The
faqusertable, which contains bcrypt password hashes for all registered users - The
faqconfigtable, which stores themain.phpMyFAQTokenadmin token and SMTP credentials
Beyond data exfiltration, payloads targeting the DELETE path can wipe arbitrary rows within the database connection's scope. This could destroy the entire faqcaptcha table, effectively locking out legitimate users from captcha-protected functionality.
Recommended Code Fix
For organizations maintaining custom forks or unable to upgrade immediately, the fix involves routing all user-controlled fields through Database::escape() before interpolation. The patched garbageCollector() implementation should follow this pattern:
$db = $this->configuration->getDb(); $userAgent = $db->escape($this->userAgent); $language = $db->escape($this->configuration->getLanguage()->getLanguage()); $ip = $db->escape($this->ip); $delete = sprintf( "DELETE FROM %sfaqcaptcha WHERE useragent = '%s' AND language = '%s' AND ip = '%s'", Database::getTablePrefix(), $userAgent, $language, $ip ); $db->query($delete);
The same escaping pattern must be applied to saveCaptcha() and any other code paths that use sprintf to construct SQL statements with user-controlled input.
Affected Systems and Versions
All versions of phpMyFAQ prior to 4.1.2 are affected. Version 4.1.2, released on April 28, 2026, addresses this vulnerability. The flaw is present in any deployment where the GET /api/captcha endpoint is publicly reachable, which is the default configuration.
Vendor Security History
phpMyFAQ has seen a notable cluster of security disclosures in early 2026, suggesting the codebase is undergoing active security review. The following table summarizes recent CVEs:
| CVE Identifier | Affected Versions | Description | Severity |
|---|---|---|---|
| CVE-2026-32629 | Prior to 4.1.1 | Unauthenticated attacker can submit a guest FAQ with an email | Unknown |
| CVE-2026-27836 | Prior to 4.0.18 | WebAuthn prepare endpoint creates new active user | Unknown |
| CVE-2026-24422 | 4.0.16 and below | Public API endpoints improperly expose sensitive user information | 7.5 HIGH |
| CVE-2026-24420 | 4.0.16 and below | Authenticated user without dlattachment permission access | Unknown |
The vendor has been responsive in issuing patches for each of these disclosures, which is a positive signal for organizations evaluating the project's security posture.



