Every CVE Search/ Get API key

CVE-2026-46364

phpMyFAQ - SQL Injection via User-Agent Header in BuiltinCaptcha

9.3 CriticalFix available

phpMyFAQ before 4.1.2 contains an unauthenticated SQL injection vulnerability in BuiltinCaptcha::garbageCollector() and BuiltinCaptcha::saveCaptcha() methods that interpolate unsanitized User-Agent headers into DELETE and INSERT queries. Unauthenticated attackers can exploit the public GET /api/captcha endpoint by crafting malicious User-Agent headers to perform time-based blind SQL injection, extracting sensitive data including user credentials, admin tokens, and SMTP credentials from the database.

Attack profile

How easy it is to exploit

Attack vector
Network
Complexity
Low
Privileges needed
None
User interaction
None

What an attacker can affect

Confidentiality
High
Integrity
High
Availability
High

Exploit likelihood

1.71%Up 1.7 points since May 16, 2026
90%50%10%1%

What each source reports

CVE List Score used 9.3

phpMyFAQ - SQL Injection via User-Agent Header in BuiltinCaptcha

phpMyFAQ before 4.1.2 contains an unauthenticated SQL injection vulnerability in BuiltinCaptcha::garbageCollector() and BuiltinCaptcha::saveCaptcha() methods that interpolate unsanitized User-Agent headers into DELETE and INSERT queries. Unauthenticated attackers can exploit the public GET /api/captcha endpoint by crafting malicious User-Agent headers to perform time-based blind SQL injection, extracting sensitive data including user credentials, admin tokens, and SMTP credentials from the database.

Record
CVE-2026-46364
CVSS 4.0
9.3 CriticalCVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N
CVSS 3.1
9.8 CriticalCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
Weakness
CWE-89
Updated
2026-11-08
EUVDEUVD-2026-30601 9.3

phpMyFAQ before 4.1.2 contains an unauthenticated SQL injection vulnerability in BuiltinCaptcha::garbageCollector() and BuiltinCaptcha::saveCaptcha() methods that interpolate unsanitized User-Agent headers into DELETE and INSERT queries. Unauthenticated attackers can exploit the public GET /api/captcha endpoint by crafting malicious User-Agent headers to perform time-based blind SQL injection, extracting sensitive data including user credentials, admin tokens, and SMTP credentials from the database.

Record
EUVD-2026-30601
CVSS 4.0
9.3 CriticalCVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N
Updated
2026-11-08
GitHub AdvisoriesGHSA-289f-fq7w-6q2w 9.8

phpMyFAQ has unauthenticated SQL injection via User-Agent header in BuiltinCaptcha

Summary

BuiltinCaptcha::garbageCollector() and BuiltinCaptcha::saveCaptcha() at phpmyfaq/src/phpMyFAQ/Captcha/BuiltinCaptcha.php:298 and :330 interpolate the User-Agent header and client IP address into DELETE and INSERT queries with sprintf and no escaping. Both methods run on every hit to the public GET /api/captcha endpoint, which requires no authentication. An unauthenticated attacker sets the User-Agent header to a crafted SQL payload and runs SLEEP(), BENCHMARK(), or time-based blind extraction against the database that backs phpMyFAQ. Verified live against 4.2.0-alpha (master at b9f25109): baseline request 147 ms, request with User-Agent: x' OR SLEEP(2) OR 'x 4.09 s (two SLEEP(2) calls, one per vulnerable sink).

Details

phpmyfaq/src/phpMyFAQ/Captcha/BuiltinCaptcha.php:112 populates two private fields from untrusted HTTP input at construction time:

$this->userAgent = $request->headers->get('user-agent');
$this->ip = $request->getClientIp();

Both fields are then dropped into sprintf() SQL templates without ever touching Database::escape() or a prepared statement.

garbageCollector() at line 298 (called on every captcha request via getCaptchaImage()):

$delete = sprintf(
    "
    DELETE FROM
        %sfaqcaptcha
    WHERE
        useragent = '%s' AND language = '%s' AND ip = '%s'",
    Database::getTablePrefix(),
    $this->userAgent,                                      // unescaped
    $this->configuration->getLanguage()->getLanguage(),
    $this->ip,                                             // unescaped
);
$this->configuration->getDb()->query($delete);

saveCaptcha() at line 330 does the same for INSERT:

$insert = sprintf(
    "INSERT INTO %sfaqcaptcha (id, useragent, language, ip, captcha_time) VALUES ('%s', '%s', '%s', '%s', %d)",
    Database::getTablePrefix(),
    $this->code,
    $this->userAgent,                                      // unescaped
    $this->configuration->getLanguage()->getLanguage(),
    $this->ip,                                             // unescaped
    $this->timestamp,
);
$this->configuration->getDb()->query($insert);

For comparison, the same file's checkCaptchaCode() at line 472 passes user input through $db->escape() before interpolation. The BuiltinCaptcha author knew about escape(); the two sinks above skip it.

Reachability

phpmyfaq/src/phpMyFAQ/Controller/Frontend/Api/CaptchaController.php:39 exposes the vulnerable flow as an unauthenticated GET:

#[Route(path: 'captcha', name: 'api.private.captcha', methods: ['GET'])]
public function renderImage(): Response
{
    if (!$this->captcha instanceof BuiltinCaptcha) {
        return new Response('', Response::HTTP_NOT_FOUND);
    }
    // ...
    $response->setContent($this->captcha->getCaptchaImage());
    return $response;
}

getCaptchaImage() calls saveCaptcha() and garbageCollector() unconditionally. No CSRF token, session, or rate limit gates the request. Any unauthenticated user hitting GET /api/captcha injects into two queries at once.

Impact surface

MySQL's query() method executes one statement per call, so the attacker cannot stack queries. Time-based blind extraction with SLEEP() or BENCHMARK() still works, and the attacker can:

  • Read any row the web user has access to through bit-by-bit IF(SUBSTR((SELECT ...),1,1)='a', SLEEP(1), 0) chains. The faquser table holds auth_source, login, and bcrypt password hashes for every registered user; faqconfig holds the main.phpMyFAQToken admin token and SMTP credentials.
  • UPDATE / DELETE arbitrary rows in the same connection's privilege scope using payloads that rewrite the DELETE's WHERE clause (for example, User-Agent: ' OR 1=1 -- deletes the entire faqcaptcha table and locks out legitimate users).

Proof of Concept

Tested against phpMyFAQ 4.2.0-alpha at master b9f25109fddb38eee19987183798638d07943f92, default install (MariaDB…

Record
GHSA-289f-fq7w-6q2w
CVSS 3.1
9.8 CriticalCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
Weakness
CWE-89
Updated
2026-11-02
GitHub AdvisoriesGHSA-ch9q-c9mp-j5gq 9.3

Duplicate Advisory: phpMyFAQ has unauthenticated SQL injection via User-Agent header in BuiltinCaptcha

Duplicate Advisory

This advisory has been withdrawn because it is a duplicate of GHSA-289f-fq7w-6q2w. This link is maintained to preserve external references.

Original Description

phpMyFAQ before 4.1.2 contains an unauthenticated SQL injection vulnerability in BuiltinCaptcha::garbageCollector() and BuiltinCaptcha::saveCaptcha() methods that interpolate unsanitized User-Agent headers into DELETE and INSERT queries. Unauthenticated attackers can exploit the public GET /api/captcha endpoint by crafting malicious User-Agent headers to perform time-based blind SQL injection, extracting sensitive data including user credentials, admin tokens, and SMTP credentials from the database.

Record
GHSA-ch9q-c9mp-j5gq
CVSS 4.0
9.3 CriticalCVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X
CVSS 3.1
9.8 CriticalCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
Weakness
CWE-89
Updated
2026-11-02
NVD 9.3

phpMyFAQ before 4.1.2 contains an unauthenticated SQL injection vulnerability in BuiltinCaptcha::garbageCollector() and BuiltinCaptcha::saveCaptcha() methods that interpolate unsanitized User-Agent headers into DELETE and INSERT queries. Unauthenticated attackers can exploit the public GET /api/captcha endpoint by crafting malicious User-Agent headers to perform time-based blind SQL injection, extracting sensitive data including user credentials, admin tokens, and SMTP credentials from the database.

Record
CVE-2026-46364
CVSS 4.0
9.3 CriticalCVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X
CVSS 3.1
9.8 CriticalCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
Weakness
CWE-89
Updated
2026-11-02
OSV 9.3

phpMyFAQ - SQL Injection via User-Agent Header in BuiltinCaptcha

phpMyFAQ before 4.1.2 contains an unauthenticated SQL injection vulnerability in BuiltinCaptcha::garbageCollector() and BuiltinCaptcha::saveCaptcha() methods that interpolate unsanitized User-Agent headers into DELETE and INSERT queries. Unauthenticated attackers can exploit the public GET /api/captcha endpoint by crafting malicious User-Agent headers to perform time-based blind SQL injection, extracting sensitive data including user credentials, admin tokens, and SMTP credentials from the database.

Record
CVE-2026-46364
CVSS 4.0
9.3 CriticalCVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N
Weakness
CWE-89
Updated
2026-11-02
OSVGHSA-289f-fq7w-6q2w 9.8

phpMyFAQ has unauthenticated SQL injection via User-Agent header in BuiltinCaptcha

Summary

BuiltinCaptcha::garbageCollector() and BuiltinCaptcha::saveCaptcha() at phpmyfaq/src/phpMyFAQ/Captcha/BuiltinCaptcha.php:298 and :330 interpolate the User-Agent header and client IP address into DELETE and INSERT queries with sprintf and no escaping. Both methods run on every hit to the public GET /api/captcha endpoint, which requires no authentication. An unauthenticated attacker sets the User-Agent header to a crafted SQL payload and runs SLEEP(), BENCHMARK(), or time-based blind extraction against the database that backs phpMyFAQ. Verified live against 4.2.0-alpha (master at b9f25109): baseline request 147 ms, request with User-Agent: x' OR SLEEP(2) OR 'x 4.09 s (two SLEEP(2) calls, one per vulnerable sink).

Details

phpmyfaq/src/phpMyFAQ/Captcha/BuiltinCaptcha.php:112 populates two private fields from untrusted HTTP input at construction time:

$this->userAgent = $request->headers->get('user-agent');
$this->ip = $request->getClientIp();

Both fields are then dropped into sprintf() SQL templates without ever touching Database::escape() or a prepared statement.

garbageCollector() at line 298 (called on every captcha request via getCaptchaImage()):

$delete = sprintf(
    "
    DELETE FROM
        %sfaqcaptcha
    WHERE
        useragent = '%s' AND language = '%s' AND ip = '%s'",
    Database::getTablePrefix(),
    $this->userAgent,                                      // unescaped
    $this->configuration->getLanguage()->getLanguage(),
    $this->ip,                                             // unescaped
);
$this->configuration->getDb()->query($delete);

saveCaptcha() at line 330 does the same for INSERT:

$insert = sprintf(
    "INSERT INTO %sfaqcaptcha (id, useragent, language, ip, captcha_time) VALUES ('%s', '%s', '%s', '%s', %d)",
    Database::getTablePrefix(),
    $this->code,
    $this->userAgent,                                      // unescaped
    $this->configuration->getLanguage()->getLanguage(),
    $this->ip,                                             // unescaped
    $this->timestamp,
);
$this->configuration->getDb()->query($insert);

For comparison, the same file's checkCaptchaCode() at line 472 passes user input through $db->escape() before interpolation. The BuiltinCaptcha author knew about escape(); the two sinks above skip it.

Reachability

phpmyfaq/src/phpMyFAQ/Controller/Frontend/Api/CaptchaController.php:39 exposes the vulnerable flow as an unauthenticated GET:

#[Route(path: 'captcha', name: 'api.private.captcha', methods: ['GET'])]
public function renderImage(): Response
{
    if (!$this->captcha instanceof BuiltinCaptcha) {
        return new Response('', Response::HTTP_NOT_FOUND);
    }
    // ...
    $response->setContent($this->captcha->getCaptchaImage());
    return $response;
}

getCaptchaImage() calls saveCaptcha() and garbageCollector() unconditionally. No CSRF token, session, or rate limit gates the request. Any unauthenticated user hitting GET /api/captcha injects into two queries at once.

Impact surface

MySQL's query() method executes one statement per call, so the attacker cannot stack queries. Time-based blind extraction with SLEEP() or BENCHMARK() still works, and the attacker can:

  • Read any row the web user has access to through bit-by-bit IF(SUBSTR((SELECT ...),1,1)='a', SLEEP(1), 0) chains. The faquser table holds auth_source, login, and bcrypt password hashes for every registered user; faqconfig holds the main.phpMyFAQToken admin token and SMTP credentials.
  • UPDATE / DELETE arbitrary rows in the same connection's privilege scope using payloads that rewrite the DELETE's WHERE clause (for example, User-Agent: ' OR 1=1 -- deletes the entire faqcaptcha table and locks out legitimate users).

Proof of Concept

Tested against phpMyFAQ 4.2.0-alpha at master b9f25109fddb38eee19987183798638d07943f92, default install (MariaDB…

Record
GHSA-289f-fq7w-6q2w
CVSS 3.1
9.8 CriticalCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
Weakness
CWE-89
Updated
2026-11-02
OSVGHSA-ch9q-c9mp-j5gq 9.3

Duplicate Advisory: phpMyFAQ has unauthenticated SQL injection via User-Agent header in BuiltinCaptcha

Duplicate Advisory

This advisory has been withdrawn because it is a duplicate of GHSA-289f-fq7w-6q2w. This link is maintained to preserve external references.

Original Description

phpMyFAQ before 4.1.2 contains an unauthenticated SQL injection vulnerability in BuiltinCaptcha::garbageCollector() and BuiltinCaptcha::saveCaptcha() methods that interpolate unsanitized User-Agent headers into DELETE and INSERT queries. Unauthenticated attackers can exploit the public GET /api/captcha endpoint by crafting malicious User-Agent headers to perform time-based blind SQL injection, extracting sensitive data including user credentials, admin tokens, and SMTP credentials from the database.

Record
GHSA-ch9q-c9mp-j5gq
CVSS 4.0
9.3 CriticalCVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X
CVSS 3.1
9.8 CriticalCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
Weakness
CWE-89
Updated
2026-11-02

Affected products

Affected packages

Affected packages
PackageAffectedFixed
thorsten/phpmyfaq
Packagist
through 4.1.1
4.1.2
phpmyfaq/phpmyfaq
Packagist
through 4.1.1
4.1.2
thorsten/phpmyfaq
Packagist
before 4.1.2, plus listed versions
2.10.0-alpha2.8.02.8.0-RC2.8.0-RC22.8.0-RC3
Show 45 moreShow less
2.8.0-RC42.8.0-alpha22.8.0-alpha32.8.0-beta2.8.0-beta22.8.0-beta32.8.12.8.102.8.112.8.122.8.132.8.142.8.152.8.162.8.172.8.182.8.192.8.22.8.202.8.212.8.222.8.232.8.242.8.252.8.262.8.272.8.282.8.292.8.32.8.42.8.52.8.62.8.72.8.82.8.92.9.02.9.0-alpha2.9.0-alpha22.9.0-alpha32.9.0-alpha42.9.0-beta2.9.0-beta22.9.0-rc2.9.0-rc22.9.0-rc3
4.1.2
phpmyfaq/phpmyfaq
Packagist
before 4.1.2, plus listed versions
2.10.0-alpha2.8.02.8.0-RC2.8.0-RC22.8.0-RC3
Show 45 moreShow less
2.8.0-RC42.8.0-alpha22.8.0-alpha32.8.0-beta2.8.0-beta22.8.0-beta32.8.12.8.102.8.112.8.122.8.132.8.142.8.152.8.162.8.172.8.182.8.192.8.22.8.202.8.212.8.222.8.232.8.242.8.252.8.262.8.272.8.282.8.292.8.32.8.42.8.52.8.62.8.72.8.82.8.92.9.02.9.0-alpha2.9.0-alpha22.9.0-alpha32.9.0-alpha42.9.0-beta2.9.0-beta22.9.0-rc2.9.0-rc22.9.0-rc3
4.1.2

Public exploits

Links only. Every CVE stores no exploit code.

Public exploits
SourceLinkDate
NucleiphpMyFAQ <= 4.1.1 - SQL Injection

History

History
RecordedChangedSources
factsEUVD
affected
first indexedCVE List, EUVD, GitHub Advisories, Nuclei, NVD, OSV

Dates are when Every CVE recorded each change. Upstream dates may differ.

In short

CVE-2026-46364 is a critical vulnerability (CVSS 9.3) in Thorsten Phpmyfaq, published May 6, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 1.71%, the 77th percentile. Fixed in thorsten/phpmyfaq 4.1.2.

References

This page doesn't list everything

Left out here: 240 versions and the rest of 2 source descriptions. The JSON record has them.

MoveEnter Open