2cdae04ddc1e46cdfc2e5e8cf479cbbbb616ad10
chmalee
  Tue Sep 22 15:55:10 2026 -0700
htmlSanitize tooltips before printing them into the page, refs #38226

diff --git src/hg/js/hgTracks.js src/hg/js/hgTracks.js
index 93dd575e16d..c6c02b7d62a 100644
--- src/hg/js/hgTracks.js
+++ src/hg/js/hgTracks.js
@@ -4489,58 +4489,59 @@
                         // CGIs now use HTML tags, e.g. "<b>Transcript:</b> ENST00000297261.7<br><b>Strand:</b>"
                         title = rightClick.mouseOverToLabel(decodeURIComponent(title));
 
                         if (title.length > maxLength) {
                             title = title.substring(0, maxLength) + "...";
                         }
 
                         if (isHgc) {
                             // For GTEx gene and UniProt mouseovers, replace title (which may be a tissue name) with 
                             // item (gene) name. Also need to unescape the urlencoded characters and the + sign.
                             let a = /i=([^&]+)/.exec(href);
                             if (a && a[1]) {
                                 title = decodeURIComponent(a[1].replace(/\+/g, " "));
                             }
                         }
+                        var titleHtml = htmlEncode(title);
 
                         if (displayItemFunctions) {
-                            o[rightClick.makeImgTag("magnify.png") + " Zoom to " +  title] = {
+                            o[rightClick.makeImgTag("magnify.png") + " Zoom to " +  titleHtml] = {
                                 onclick: function(menuItemClicked, menuObject) {
                                             rightClick.hit(menuItemClicked, menuObject,
                                                     "selectWholeGene"); return true;
                                           }
                                 };
-                            o[rightClick.makeImgTag("highlight.png") + " Highlight " + title] =
+                            o[rightClick.makeImgTag("highlight.png") + " Highlight " + titleHtml] =
                                 {   onclick: function(menuItemClicked, menuObject) {
                                         rightClick.hit(menuItemClicked, menuObject,
                                                        "highlightItem");
                                         return true;
                                     }
                                 };
                             var itemForColor = rightClick.itemFromHref(href);
                             if (hgTracks.canColorItems && itemForColor) {
-                                o[rightClick.makeImgTag("palette.png") + " Color " + title + "..."] =
+                                o[rightClick.makeImgTag("palette.png") + " Color " + titleHtml + "..."] =
                                     {   onclick: function(menuItemClicked, menuObject) {
                                             rightClick.hit(menuItemClicked, menuObject,
                                                            "colorThisItem");
                                             return true;
                                         }
                                     };
                                 if (rightClick.findItemColor(itemForColor.track,
                                                              itemForColor.name)) {
                                     o[rightClick.makeImgTag("palette.png") +
-                                            " Remove color from " + title] =
+                                            " Remove color from " + titleHtml] =
                                         {   onclick: function(menuItemClicked, menuObject) {
                                                 rightClick.hit(menuItemClicked, menuObject,
                                                                "removeItemColor");
                                                 return true;
                                             }
                                         };
                                 }
                             }
                             //o[rightClick.makeImgTag("highlight.png") + " Highlight THIS item"] = 
                             //    {   onclick: function(menuItemClicked, menuObject) {
                             //            rightClick.hit(menuItemClicked, menuObject,
                             //                           "highlightThisItem"); 
                             //            return true;
                             //        }
                             //    };
@@ -4593,60 +4594,60 @@
                                             rightClick.hit(menuItemClicked, menuObject,
                                                         "zoomCodon",
                                                         {name: name, table: table, 'chrom': hgTracks.chromName});
                                             return true;}
                                     };
                                         o[rightClick.makeImgTag("magnify.png")+" Enter exon to zoom to..."] =
                                         {   onclick: function(menuItemClicked, menuObject) {
                                                 rightClick.hit(menuItemClicked, menuObject,
                                                             "zoomExon",
                                                             {name: name, table: table, 'chrom': hgTracks.chromName});
                                                 return true;}
                                         };
                                     }
                                 }
                             }
-                            o[rightClick.makeImgTag("dnaIcon.png")+" Get DNA for "+title] = {
+                            o[rightClick.makeImgTag("dnaIcon.png")+" Get DNA for "+titleHtml] = {
                                 onclick: function(menuItemClicked, menuObject) {
                                     rightClick.hit(menuItemClicked, menuObject, "getDna");
                                     return true; }
                             };
                         }
                         o[rightClick.makeImgTag("bookOut.png")+
                                                 " Open details page in new window..."] = {
                             onclick: function(menuItemClicked, menuObject) {
                                 rightClick.hit(menuItemClicked, menuObject, "openLink");
                                 return true; }
                         };
                         any = true;
                     }
                     if (href && href.length  > 0 && href.indexOf("i=mergedItem") === -1) {
                         // Add "Show details..." item
                         if (title.indexOf("Click to alter ") === 0) {
                             // suppress the "Click to alter..." items
                         } else if (rightClick.selectedMenuItem.href.indexOf("cgi-bin/hgTracks")
                                                                                         !== -1) {
                             // suppress menu items for hgTracks links (e.g. Next/Prev map items).
                         } else {
                             var item;
                             if (title === "zoomInMore")
                                 // avoid showing menu item that says
                                 // "Show details for zoomInMore..." (redmine 2447)
                                 item = rightClick.makeImgTag("book.png") + " Show details...";
                             else
                                 item = rightClick.makeImgTag("book.png")+" Show details for "+
-                                       title + "...";
+                                       htmlEncode(title) + "...";
                             o[item] = {onclick: function(menuItemClicked, menuObject) {
                                        rightClick.hit(menuItemClicked,menuObject,"followLink");
                                        return true; }
                             };
                             any = true;
                         }
                     }
                     if (any) {
                         menu.push($.contextMenu.separator);
                         menu.push(o);
                     }
                 }
             }