Introduction
This post covers another stored XSS vulnerability in ProjeQtOr, this time through file upload.
«««< HEAD I already introduced ProjeQtOr and why this kind of application can contain sensitive business data in the first article of the series: From login to admin : CVE-2026-41462 .
I already introduced ProjeQtOr and why this kind of application can contain sensitive business data in the first article of the series: From login to admin : CVE-2026-41462 .
dev
The issue here is simple: uploaded files are user-controlled content, and user-controlled content should not be served back as trusted executable content.
Vulnerability summary
The vulnerability was related to the file upload validation logic, especially the checkValidFileName() function.
The application performed some checks on filenames and dangerous extensions, but the validation did not properly prevent HTML files from being uploaded.
In practice, this means an attacker could upload a file that would later be interpreted by the browser as HTML. If another user opened the uploaded file URL, JavaScript embedded in that file could execute in their browser.
Attack surface
The vulnerability required an authenticated attacker able to upload files through the application.
The victim interaction was passive: the victim only had to access the uploaded file URL or be redirected to it.
The impact is similar to other stored XSS vulnerabilities, but the delivery method is different. Instead of injecting content into a field, the attacker abuses the file upload feature to host active browser content.
Depending on the victim’s privileges and browser context, this could lead to session compromise, actions performed on behalf of the victim, or phishing attacks within the trusted application interface.
This is especially important when uploaded files are hosted on the same domain as the main application. In that case, browser trust boundaries become much weaker.
Proof of concept
No malicious file content is provided in this article.
The important point is that accepting and serving active HTML content from a file upload feature can turn a simple upload into a stored XSS vector.
Recommended fix
The upload feature should enforce strict validation and safe serving behavior.
Recommended fixes include:
- block active extensions such as
.html,.htm,.jsand similar formats when not required; - validate the MIME type server-side;
- store uploaded files outside of the web root;
- force download with
Content-Disposition: attachmentwhen files should not be rendered; - set safe
Content-Typeheaders; - randomize stored filenames;
- apply a strict Content Security Policy.
File upload security is not only about preventing PHP or server-side code execution. Client-side execution matters too.
Conclusion
This vulnerability shows how file upload features can become dangerous even without server-side code execution.
If an application lets users upload content and then serves it back from a trusted origin, browsers may treat that content as part of the application. That is why uploaded files should be isolated, restricted and served with safe headers by default.
This was the last vulnerability we found in ProjeQtOr during this research, I hope you enjoyed reading about them as much as I enjoyed finding and analyzing them. If you have any questions or want to discuss these vulnerabilities, feel free to reach out! I will be happy to share more details and insights.
Thanks again to the ProjeQtOr team for their responsiveness and professionalism during the disclosure process, to Yasha for the idea, and to you for reading.
I hope to be back soon with more interesting research and vulnerabilities to share. Stay tuned!
Disclaimer
This post is for educational and defensive security purposes only. Do not test this vulnerability on systems you do not own or have explicit authorization to assess.