An unauthenticated attacker can submit a guest FAQ with an email address that is syntactically valid per RFC 5321 (quoted local part) yet contains raw HTML — for example "<script>alert(1)</script>"@evil.com. PHP's FILTERVALIDATEEMAIL accepts this email as valid. The email is stored in the database without HTML sanitization and later rendered in the admin FAQ editor template using Twig's |raw filter, which bypasses auto-escaping entirely.
phpmyfaq/src/phpMyFAQ/Controller/Frontend/Api/FaqController.php:99 $email = trim((string) Filter::filterVar($data->email, FILTERVALIDATEEMAIL)); PHP accepts "<script>alert(1)</script>"@evil.com as a valid email (RFC 5321 allows <, > inside quoted local parts). Confirmed: "<script>alert(1)</script>"@evil.com => string (valid, not false)
phpmyfaq/src/phpMyFAQ/Faq.php — email retrieved directly as $row->email from the database.
phpmyfaq/assets/templates/admin/content/faq.editor.twig:296 <input type="email" name="email" id="email" value="{{ faqData['email'] | raw }}" class="form-control">
Affected version: 4.2.0-alpha, commit f0dc86c8f
The reproduction of the vulnerability was implemented with the help of AI while reviewing the source code to generate the proof-of-concept. Please kindly note this for reference. Since the vulnerability has already been confirmed directly in the source code, the proof-of-concept code may be considered as a reference only.
Please extract the attached compressed file and proceed. poc.zip
docker compose -f docker-compose.yml up -d mariadb php-fpm nginx
Access http://localhost:8888/admin/
<img width="1388" height="239" alt="스크린샷 2026-03-12 오후 11 42 52" src="https://github.com/user-attachments/assets/b6d5446f-4eba-4cb2-9284-1bca4855142e" /> <img width="1171" height="92" alt="스크린샷 2026-03-12 오후 11 16 17" src="https://github.com/user-attachments/assets/3578e429-7106-4616-92ed-4167816d40f0" />
When an administrator opens /admin/faq/edit/{id}/{lang} to review the pending FAQ, the injected script executes in the admin's browser context. This allows an attacker to:
The attack chain requires no authentication. By default, records.allowNewFaqsForGuests=true allows unauthenticated FAQ submission, and records.defaultActivation=false guarantees the administrator must visit the edit page to review it.
Note on captcha: The built-in captcha is enabled by default when the PHP gd extension is present (spam.enableCaptchaCode=true). This prevents fully automated exploitation but does not prevent a targeted manual attack — an attacker can solve the captcha once and submit the payload.
wooseokdotkim
{
"cwe_ids": [
"CWE-20",
"CWE-79"
],
"github_reviewed": true,
"github_reviewed_at": "2026-03-31T22:48:45Z",
"nvd_published_at": "2026-04-02T15:16:38Z",
"severity": "MODERATE"
}