Apr 2, 2026·7 min read·3 visits
A bypass in phpMyFAQ's SVG sanitizer allows authenticated users to inject malicious JavaScript via HTML entity-encoded attributes. This Stored XSS vulnerability can lead to privilege escalation when an administrator views the compromised FAQ. Fixed in version 4.1.1.
phpMyFAQ versions prior to 4.1.1 contain a vulnerability in the SVG sanitizer component. The application relies on a blacklist regular expression that fails to properly process HTML entity-encoded attributes, allowing an attacker with Editor privileges to upload a malicious SVG. This flaw enables Stored Cross-Site Scripting (XSS), which can result in privilege escalation to Administrator.
The vulnerability exists within the src/phpMyFAQ/SvgSanitizer.php component of the phpMyFAQ application. This component is responsible for parsing uploaded Scalable Vector Graphics (SVG) files and stripping potentially dangerous attributes to prevent Cross-Site Scripting (XSS). SVG files are natively supported by modern web browsers and can embed active content, making robust sanitization a strict requirement for secure file upload handlers.
The core issue is a Stored XSS vulnerability classified under CWE-79 and CWE-116. The application's sanitization logic attempts to filter out malicious URL protocols, specifically targeting the javascript: pseudo-protocol. However, the implementation does not decode HTML entities before applying its regular expression checks, creating a parsing differential between the server-side sanitizer and the client-side browser.
To exploit this vulnerability, an attacker requires the edit_faq permission, typically assigned to the Editor role. By uploading a crafted SVG file containing entity-encoded malicious JavaScript, the attacker persists the payload in the application database. The execution occurs when a victim accesses the affected FAQ entry, allowing the attacker to execute arbitrary scripts in the victim's session context.
The primary risk associated with this vulnerability is privilege escalation. If an administrator views the manipulated FAQ entry, the injected script executes with their elevated privileges. This allows the attacker to perform administrative actions, such as altering configuration settings, exfiltrating sensitive data, or granting administrative rights to other accounts.
The root cause of CVE-2026-34974 lies in the use of a blacklist-based regular expression for sanitizing user-controlled input without prior canonicalization. The SvgSanitizer.php script inspects SVG tags and attributes for known dangerous strings. Specifically, it searches for the literal string javascript: within attributes like href to prevent script execution.
Modern web browsers implement robust XML and HTML parsing engines that automatically decode HTML entities within attribute values before interpreting the attribute's content. This means that a string encoded using decimal or hexadecimal entities (e.g., ja for ja) is functionally identical to the raw string from the browser's perspective. The browser decodes the entities and executes the resulting JavaScript protocol.
The phpMyFAQ sanitizer fails to account for this client-side decoding step. Because the regular expression evaluates the raw, encoded input string rather than the canonicalized decoded string, it does not detect the presence of the javascript: protocol. The sanitizer determines the input is safe and allows the file upload to proceed.
This discrepancy between how the security control interprets the data and how the execution environment processes the data forms the basis of the sanitizer bypass. Blacklist approaches are inherently fragile in this context, as attackers can utilize various encoding mechanisms to obfuscate the malicious payload while maintaining its viability in the target environment.
The vulnerable implementation in versions prior to 4.1.1 relies on string matching and regular expressions to strip dangerous content. The application processes the uploaded SVG as a standard string. When checking an anchor tag's href attribute, it applies a regex similar to preg_match('/javascript:/i', $attributeValue) or explicitly replaces the string.
An attacker bypasses this check by providing a heavily encoded payload. Instead of supplying <a href="javascript:alert(1)">, the attacker encodes the protocol string. The application evaluates javascript:alert(1). The regex fails to match the literal javascript:, and the payload successfully passes the sanitization routine.
The patch introduced in phpMyFAQ 4.1.1 comprehensively redesigns the sanitization logic. The development team replaced the fragile regex-based approach with a structured, DOM-based sanitization process. The new implementation parses the SVG as an XML document, allowing the application to traverse the node tree and explicitly evaluate elements and attributes.
Crucially, the updated sanitizer implements canonicalization and an allow-list methodology. The application now decodes HTML entities before performing validation checks. Furthermore, instead of blacklisting javascript:, the application strictly enforces an allow-list of permitted protocols (e.g., http:, https:, mailto:). Attributes containing unrecognized protocols are systematically stripped from the document tree before it is saved.
Exploitation begins with an attacker securing access to an account possessing the edit_faq permission. This permission allows the user to create or modify FAQ entries and attach files. The attacker leverages this legitimate functionality to deliver the malicious payload to the server.
The attacker constructs a specialized SVG document containing an embedded hyperlink. The hyperlink's href attribute is populated with a JavaScript payload, but the protocol declaration is obscured using hexadecimal HTML entities. This ensures the payload evades the server-side regex checks.
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
<a href="javascript:fetch('/admin/api/v1/users/1', {method:'PUT',body:'role=admin'})">
<circle cx="50" cy="50" r="40" fill="red" />
</a>
</svg>The attacker uploads the crafted SVG and embeds it within a highly visible FAQ entry. The execution phase is deferred until a privileged user, such as an administrator, views the compromised page. When the administrator interacts with the SVG element, the browser decodes the entities and executes the fetch API call, which dispatches a forged request to the administrative API to elevate the attacker's account privileges.
The exploitation of CVE-2026-34974 results in arbitrary JavaScript execution within the web browser of the victim. Because the payload is executed in the context of the phpMyFAQ application, the script can access sensitive session data, including cookies, local storage, and CSRF tokens associated with the victim's authenticated session.
The CVSS v3.1 vector is CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:N, resulting in a base score of 5.4 (Medium). The Scope component is defined as Changed (S:C) because the vulnerability originates in the application's backend but impacts the client's browser environment. The Attack Vector is Network (AV:N), and User Interaction is Required (UI:R) because the victim must view the specific payload.
The primary security impact is the potential for horizontal or vertical privilege escalation. An attacker with Editor access can target an Administrator. By injecting a payload that programmatically interacts with the application's administrative interfaces, the attacker can silently grant themselves full administrative control over the platform.
While the severity is categorized as Medium due to the authentication and user interaction prerequisites, the practical consequences for organizations relying on phpMyFAQ are severe. Complete compromise of the application's administrative layer can lead to broad data modification and further exploitation of the underlying web infrastructure.
The definitive remediation for CVE-2026-34974 is upgrading the phpMyFAQ installation to version 4.1.1 or later. The patch completely replaces the vulnerable regex-based sanitizer with a robust DOM-based parser that enforces an explicit protocol allow-list and correctly handles HTML entity decoding. Administrators should apply this update immediately to eliminate the attack surface.
If immediate patching is not technically feasible, administrators can apply temporary mitigation strategies. The most effective workaround is to disable SVG file uploads entirely within the phpMyFAQ configuration. By restricting allowed file types to raster image formats (e.g., PNG, JPEG), the application prevents the ingestion of the XML-based vector graphic payloads required for this exploit.
Security teams should conduct a retrospective review of existing attachments to detect potential compromise. Administrators can audit the application database and file storage for SVG files containing hexadecimal encoding structures, specifically searching for the pattern j or decimal equivalent j near href attributes.
# Nuclei Detection Snippet
id: CVE-2026-34974-Detection
info:
name: phpMyFAQ SVG Sanitizer Bypass (XSS)
author: security_researcher
severity: medium
http:
- method: GET
path:
- "{{BaseURL}}/index.php"
matchers:
- type: regex
part: body
regex:
- 'phpMyFAQ (4\.0\.|4\.1\.0)'The provided Nuclei template facilitates the rapid identification of vulnerable phpMyFAQ versions across a network environment. It analyzes the HTTP response body for version strings matching the affected 4.0.x and 4.1.0 branches.
CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
phpMyFAQ thorsten | < 4.1.1 | 4.1.1 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-79 |
| Attack Vector | Network |
| CVSS Score | 5.4 |
| Impact | Stored XSS / Privilege Escalation |
| Exploit Status | Proof of Concept (PoC) Available |
| Authentication | Required (Editor Privileges) |
The software does not neutralize or incorrectly neutralizes user-controllable input before it is placed in output that is used as a web page that is served to other users.