3f7bd2d5d5d8c71665acbd21926a2333afe2c674
chmalee
  Wed Sep 23 11:20:20 2026 -0700
Fix one last tooltip encoding spot after nightly code review, refs #38226

diff --git src/hg/js/utils.js src/hg/js/utils.js
index 53836611633..ed5271cc1b3 100644
--- src/hg/js/utils.js
+++ src/hg/js/utils.js
@@ -4452,31 +4452,31 @@
 }
 
 function hideMouseoverText(ele) {
     /* Actually hides the tooltip text */
     ele.classList.remove("isShown");
     ele.style.opacity = "0";
     ele.style.visibility = "hidden";
 }
 
 function titleTagToMouseover(mapEl) {
     /* for a given area tag, extract the title text into a div that can be positioned
     * like a standard tooltip mouseover next to the item */
     if (mapEl.dataset.tooltip)
         addMouseover(mapEl, mapEl.dataset.tooltip);
     else
-        addMouseover(mapEl, mapEl.title);
+        addMouseover(mapEl, htmlEncode(mapEl.title));
 }
 
 function gbShowTimingDialog(serverRows, clientRows) {
     /* Pop up a small modal that breaks down where a page spent its time.  Shared by the
      * client-rendered CGI pages (hgBlat, hgSession, ...) that emit a "timing" array when loaded
      * with &measureTiming=1.  serverRows and clientRows are each an array of {label, ms} (either may
      * be null/empty); the server list normally ends with a {label:"total"} row from the C side.
      * Renders one gbTable with a proportional bar per row, styled by the .gbTiming* rules in
      * gbModern.css.  Reuses the .gbModalBg/.gbModal machinery; closes on Close, Esc, backdrop. */
     serverRows = serverRows || [];
     clientRows = clientRows || [];
     // Scale the bars to the largest single interval (ignoring the grand-total rows, which would
     // otherwise dwarf every step).  Fall back to 1 to avoid divide-by-zero on an all-zero page.
     var maxMs = 1;
     function scan(rows) {