6d28e748f8aee8c252386600fc93d7692aa6929d braney Wed Sep 2 10:39:13 2026 -0700 hgTracks: don't escape the Track Search title twice, refs #38172 The Track Search page built its blue bar title with htmlEncode() on the organism and the freeze name, then handed it to webStartWrapperDetailedNoArgs. That call prints the title through htmlTextOut, which already escapes & < > and the double quote, so the ampersand starting each entity htmlEncode() wrote was escaped a second time and the page printed the entity instead of the character. Every assembly whose dbDb description carries a '/' showed it: hg38 read "Search for Tracks in the Human Dec. 2013 (GRCh38/hg38) Assembly". The title lands in element text between two divs rather than in an attribute, so htmlTextOut covers it on its own and the encode here is not needed. Checked against the assembly hub case that prompted the encode in the first place: a hub whose genomes.txt organism and description hold markup still comes back as text in the blue bar. Found by Max in the v503 Preview II code review. diff --git src/hg/hgTracks/searchTracks.c src/hg/hgTracks/searchTracks.c index 04f75100073..a9ec02e061e 100644 --- src/hg/hgTracks/searchTracks.c +++ src/hg/hgTracks/searchTracks.c @@ -1047,33 +1047,37 @@ for (group = groupList; group != NULL; group = group->next) { groupTrackListAddSuper(cart, group, superHash, trackHash); if (group->trackList != NULL) { groups[numGroups] = cloneString(group->name); // a hub group's label is built from the hub's shortLabel and its groups.txt label labels[numGroups] = htmlEncode(group->label); numGroups++; if (numGroups >= ArraySize(groups)) internalErr(); } } hashFree(&superHash); -// on an assembly hub the organism and the freeze name both come from the hub +// On an assembly hub the organism and the freeze name both come from the hub, but they are +// not escaped here: webStartWrapperDetailedNoArgs puts the title through htmlTextOut, which +// escapes & < > and the double quote for us. Escaping it a second time printed the entity +// instead of the character, so every assembly with a '/' in its description read +// "(GRCh38/hg38)" in the blue bar. safef(buf, sizeof(buf),"Search for Tracks in the %s %s Assembly", - htmlEncode(organism), htmlEncode(hFreezeFromDb(database))); + organism, hFreezeFromDb(database)); webStartWrapperDetailedNoArgs(cart, database, "", buf, FALSE, FALSE, FALSE, FALSE); hPrintf("
"); hPrintf("
\n\n", hgTracksName(),TRACK_SEARCH_FORM,TRACK_SEARCH_FORM); cartSaveSession(cart); // Creates hidden var of hgsid to avoid bad voodoo safef(buf, sizeof(buf), "%lu", clock1()); cgiMakeHiddenVar("hgt_", buf); // timestamps page to avoid browser cache hPrintf("\n", database); hPrintf("\n", TRACK_SEARCH_CURRENT_TAB, currentTab); hPrintf("\n",TRACK_SEARCH_DEL_ROW); hPrintf("\n",TRACK_SEARCH_ADD_ROW);