304e190d0af4be54569ac20edc26999673c44f8b
braney
  Tue Aug 18 11:05:19 2026 -0700
hgTrackUi, hui: encode trackDb-derived label text consistently, refs #38123

diff --git src/hg/hgTrackUi/hgTrackUi.c src/hg/hgTrackUi/hgTrackUi.c
index 4a883081e32..e664821afe3 100644
--- src/hg/hgTrackUi/hgTrackUi.c
+++ src/hg/hgTrackUi/hgTrackUi.c
@@ -3917,32 +3917,34 @@
                        "(<A HREF=\"%s?%s=%s&db=%s&c=%s&hgTracksConfigPage=configure"
                        "&hgtgroup_%s_close=0#%sGroup\" title='%s tracks in track configuration "
                        "page'><IMG height=12 src='../images/ab_up.gif'>All %s%s</A>)</B>",
                        hgTracksName(), cartSessionVarName(), cartSessionId(cart),database,chromosome,
                        tdb->grp,tdb->grp,grp->label,grp->label,
                        endsWith(grp->label," Tracks")?"":" tracks");
                 break;
                 }
             }
         grpFreeList(&grps);
         }
 
     // incoming links from Google searches can go directly to a composite child trackUi page: tell users 
     // that they're inside a container now and can go back up the hierarchy
     if (tdbGetComposite(tdb)) {
-        printf("<p>This track is a subtrack of the composite container track \"%s\".<br>", tdb->parent->shortLabel);
-        printf("<a href='hgTrackUi?db=%s&c=%s&g=%s'>Click here</a> to display the \"%s\" container configuration page.", database, chromosome, tdb->parent->track, tdb->parent->shortLabel);
+        // shortLabel comes from trackDb, which a track hub controls, escape
+        printf("<p>This track is a subtrack of the composite container track \"%s\".<br>",
+               htmlEncode(tdb->parent->shortLabel));
+        printf("<a href='hgTrackUi?db=%s&c=%s&g=%s'>Click here</a> to display the \"%s\" container configuration page.", database, chromosome, tdb->parent->track, htmlEncode(tdb->parent->shortLabel));
     }
 
     }
 
 puts("<BR><BR>");
 
 if (tdbIsSuperTrackChild(tdb))
     showSupertrackInfo(tdb);
 
 if (ct && sameString(tdb->type, "maf"))
     tdb->canPack = TRUE;
 else if (sameString(tdb->track, WIKI_TRACK_TABLE))
     // special case wikiTrack (there's no trackDb entry); fixes redmine 2395
     tdb->canPack = TRUE;
 else if (sameString(tdb->type, "halSnake"))
@@ -4604,47 +4606,49 @@
     tdb = dupTdbFrom(tdb, dup);
     }
 
 
 if(cartOptionalString(cart, "ajax"))
     {
     // html is going to be used w/n a dialog in hgTracks.js so serve up stripped down html
     // still need CSP2 header for security
     printf("%s", getCspMetaHeader());
     trackUi(tdb, tdbList, ct, TRUE);
     cartRemove(cart,"ajax");
     jsInlineFinish();
     }
 else
     {
-    char title[1000];
+    // htmlNoEscape() below lets the <span> through, so the labels themselves have to be
+    // escaped here - they come from trackDb, which a track hub controls
+    struct dyString *title = dyStringNew(0);
     if (tdb->parent)
         {
-        safef(title, sizeof title, 
+        dyStringPrintf(title,
                         // TODO: replace in-line styling with class
                 "<span style='background-color: #c3d4f4; "
                     "padding-left: 10px; padding-right: 10px;"
                     "margin-right: 10px; margin-left: -8px;'>"
                        "%s</span> %s", 
-                tdb->parent->shortLabel, tdb->shortLabel);
+                htmlEncode(tdb->parent->shortLabel), htmlEncode(tdb->shortLabel));
         }
     else
-        safef(title, sizeof title, "%s", tdb->shortLabel);
+        dyStringPrintf(title, "%s", htmlEncode(tdb->shortLabel));
     char *titleEnd = (tdbIsSuper(tdb) ? "Tracks" :
                tdbIsDownloadsOnly(tdb) ? DOWNLOADS_ONLY_TITLE : "Track Settings");
     htmlNoEscape();     // allow HTML tags to format title blue bar (using short label)
-    cartWebStart(cart, database, "%s %s", title, titleEnd);
+    cartWebStart(cart, database, "%s %s", title->string, titleEnd);
     htmlDoEscape();
     trackUi(tdb, tdbList, ct, FALSE);
     printf("<BR>\n");
     jsonPrintGlobals();
     webEnd();
     }
 }
 
 char *excludeVars[] = { "submit", "Submit", "g", "fileUrl", "track", "sourceDb", NULL, "ajax", NULL,};
 
 int main(int argc, char *argv[])
 /* Process command line. */
 {
 long enteredMainTime = clock1000();
 /* 0, 0, == use default 10 second for warning, 20 second for immediate exit */