Server side cross-site scripting In phpmyfaq/phpmyfaq

Description

phpMyFAQ is Vulnerable to Stored XSS via Unsanitized Email Field in Admin FAQ Editor

Summary

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 ""@evil.com. PHP's FILTER_VALIDATE_EMAIL 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.

Details

    PHP FILTER_VALIDATE_EMAIL accepts RFC-valid quoted local parts with dangerous characters

phpmyfaq/src/phpMyFAQ/Controller/Frontend/Api/FaqController.php:99 $email = trim((string) Filter::filterVar($data->email, FILTER_VALIDATE_EMAIL)); PHP accepts ""@evil.com as a valid email (RFC 5321 allows <, > inside quoted local parts). Confirmed: ""@evil.com => string (valid, not false)

    Email stored raw without HTML sanitization

phpmyfaq/src/phpMyFAQ/Faq.php — email retrieved directly as $row->email from the database.

    Admin Twig template renders email with |raw

phpmyfaq/assets/templates/admin/content/faq.editor.twig:296

Affected version: 4.2.0-alpha, commit f0dc86c8f

PoC

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 down -v)

    docker compose -f docker-compose.yml up -d mariadb php-fpm nginx

    bash exploit.sh


    Access http://localhost:8888/admin/

    Log in with admin / Admin1234!

    After logging in, check whether the URL remains http://localhost:8888/admin/

    Go to Content → FAQ Administration → edit "poc" → alert popup should appear If it does not appear, you can also access it directly via: http://localhost:8888/admin/faq/edit/1/en

스크린샷 2026-03-12 오후 11 42 52 스크린샷 2026-03-12 오후 11 16 17

Impact

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:

    Steal the administrator's session cookie → full admin account takeover

    Perform arbitrary admin actions (create users, modify content, change configuration)

    Pivot to further attacks on the server

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.

Credits

wooseokdotkim

Mitigation

Update Impact

Minimal update. May introduce new vulnerabilities or breaking changes.

Ecosystem
Package
Affected version
Patched versions