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

diff --git src/hg/hgTracks/simpleTracks.c src/hg/hgTracks/simpleTracks.c
index c82fcfef41b..9e026bdb55b 100644
--- src/hg/hgTracks/simpleTracks.c
+++ src/hg/hgTracks/simpleTracks.c
@@ -29,30 +29,31 @@
 #include "grp.h"
 #include "chromColors.h"
 #include "hgTracks.h"
 #include "subText.h"
 #include "cds.h"
 #include "mafTrack.h"
 #include "wigCommon.h"
 #include "hui.h"
 #include "imageV2.h"
 #include "bigBed.h"
 #include "htmshell.h"
 #include "kxTok.h"
 #include "hash.h"
 #include "decorator.h"
 #include "decoratorUi.h"
+#include "htmlSanitize.h"
 
 #ifndef GBROWSE
 #include "encode.h"
 #include "expRatioTracks.h"
 #include "hapmapTrack.h"
 #include "retroGene.h"
 #include "switchGear.h"
 #include "variation.h"
 #include "wiki.h"
 #include "wormdna.h"
 #include "aliType.h"
 #include "agpGap.h"
 #include "cgh.h"
 #include "bactigPos.h"
 #include "genePred.h"
@@ -1125,33 +1126,37 @@
     return TRUE;
 if (isCenterLabelConditionallySeen(track))
     return TRUE;
 return FALSE;
 }
 
 void mapStatusMessage(char *format, ...)
 /* Write out stuff that will cause a status message to
  * appear when the mouse is over this box. */
 {
 va_list args;
 va_start(args, format);
 struct dyString *dy = dyStringNew(0);
 dyStringVaPrintf(dy, format, args);
 va_end(args);
+char *sanitized = htmlSanitize(dy->string);
 char *encoded = attributeEncode(dy->string);
-hPrintf(" TITLE=\"%s\" data-tooltip=\"%s\"", encoded, encoded);
+char *encSanitized = attributeEncode(sanitized);
+hPrintf(" TITLE=\"%s\" data-tooltip=\"%s\"", encoded, encSanitized);
 freeMem(encoded);
+freeMem(sanitized);
+freeMem(encSanitized);
 dyStringFree(&dy);
 }
 
 void mapBoxReinvoke(struct hvGfx *hvg, int x, int y, int width, int height,
                     struct track *track, boolean toggle, char *chrom,
                     long start, long end, char *message, char *extra)
 /* Print out image map rectangle that would invoke this program again.
  * If track is non-NULL then put that track's id in the map item.
  * if toggle is true, then toggle track between full and dense.
  * If chrom is non-null then jump to chrom:start-end.
  * Add extra string to the URL if it's not NULL */
 {
 struct dyString *ui = uiStateUrlPart(toggle ? track : NULL);
 struct dyString *id = dyStringNew(0);
 if(track)
@@ -1320,31 +1325,37 @@
             if (withHgsid)
                 hPrintf("&%s", cartSidUrlString(cart));
             }
         else
             {
             hPrintf("HREF=\"%s&o=%d&t=%d&g=%s&i=%s&c=%s&l=%d&r=%d&db=%s&pix=%d",
                 hgcNameAndSettings(), start, end, encodedTrack, encodedItem,
                     chromName, winStart, winEnd,
                     database, tl.picWidth);
             }
         if (extra != NULL)
             hPrintf("&%s", extra);
         hPrintf("\" ");
         if (statusLine != NULL)
             {
-            hPrintf(" TITLE='%s' data-tooltip='%s' ", item, statusLine);
+            char *encItem = attributeEncode(item);
+            char *sanitized = htmlSanitize(statusLine);
+            char *encoded = attributeEncode(sanitized);
+            hPrintf(" TITLE='%s' data-tooltip='%s' ", encItem, encoded);
+            freeMem(sanitized);
+            freeMem(encoded);
+            freeMem(encItem);
             }
         hPrintf("%s>\n", dyStringContents(id));
         }
     freeMem(encodedItem);
     freeMem(encodedTrack);
     }
 dyStringFree(&id);
 }
 
 void mapBoxHc(struct hvGfx *hvg, int start, int end, int x, int y, int width, int height,
               char *track, char *item, char *statusLine)
 /* Print out image map rectangle that would invoke the hgc (human genome click)
  * program. */
 {
 mapBoxHgcOrHgGene(hvg, start, end, x, y, width, height, track, item, statusLine, NULL, FALSE, NULL);