Introduction
This article focuses on a stored XSS vulnerability we identified in ProjeQtOr.
«««< HEAD For more context about the software itself, I already covered that in the first article of this series: From login to admin : CVE-2026-41462 .
For more context about the software itself, I already covered that in the first article of this series: From login to admin : CVE-2026-41462 .
dev
This time, the vulnerable behavior was linked to HTML filtering. The application tried to detect dangerous HTML patterns, but the protection was not strong enough.
Vulnerability summary
The issue was found in the checkValidHtmlText() function inside Security.php.
The function attempted to detect some dangerous patterns, such as script tags or common JavaScript event handlers. However, it returned the original string and did not properly encode or sanitize the content before rendering it.
A simplified version of the logic looked like this:
1if (preg_match('/<script/', pq_nvl(pq_strtolower($string))) == true) {
2 traceHack("invalid sequence in html text - $string");
3}
4
5return $string;
The problem is that blacklist-based filtering is fragile. Blocking a few keywords does not make HTML safe.
Modern XSS payloads can use many different syntaxes, contexts and browser behaviors. If the application stores user-controlled HTML and later renders it without proper output encoding, JavaScript execution may still be possible.
Never rely on regex-based blacklists to protect against XSS. The safest approach is to encode output by default and only allow rich HTML through a real sanitizer.
Attack surface
This was a stored XSS issue.
That means the malicious content could be saved inside the application and executed later when another user viewed the affected content.
The vulnerability required a victim to view the stored content, but once triggered, the script would execute in the context of the victim’s browser session.
Depending on the victim’s privileges, this could lead to:
- session compromise;
- actions performed on behalf of the victim;
- phishing inside the trusted application interface;
- modification of displayed content;
- data theft from pages accessible to the victim.
Even if this run in client-side, XSS is a very common and impactful vulnerability that can lead to data breaches, account takeovers and other attacks.
Recommended fix
The application should not rely on regex-based blacklists to protect against XSS.
A better approach, would be to encode the output by default, using PHP function like htmlspecialchars() like this:
1echo htmlspecialchars($userInput, ENT_QUOTES | ENT_HTML5, 'UTF-8');
Or if the application needs to allow some HTML tags, it should use a proper HTML sanitizer library that can parse and clean the HTML content, such as HTML Purifier .
A strict CSP (Content Security Policy) can also be implemented as an additional layer of defense.
Conclusion
This article is a reminder that blocking script tags is not enough to prevent XSS.
And betweens the different browser quirks, or some special contexts, there are many ways to execute JavaScript without using the <script> tag directly. 🦐🦐🦐
Disclaimer
This article is for educational purposes only. Do not attempt to exploit this vulnerability on systems without explicit permission.