764e1dff7737828ea9d3395804db520628e91a69 braney Tue Aug 18 10:59:46 2026 -0700 hgTracks: encode assembly and group header text consistently, refs #38123 diff --git src/hg/hgTracks/hgTracks.c src/hg/hgTracks/hgTracks.c index 442d61d3c3f..71f2ae89df5 100644 --- src/hg/hgTracks/hgTracks.c +++ src/hg/hgTracks/hgTracks.c @@ -9712,57 +9712,61 @@ * narrow */ hPrintf("<DIV STYLE=\"white-space:nowrap;\">\n"); printMenuBar(); //menuBarAppendExtTools(); /* Show title */ freezeName = hFreezeFromDb(database); if(freezeName == NULL) freezeName = "Unknown"; hPrintf("<span id='assemblyName' style='font-size:large;'><B>"); // for these assemblies, we do not display the year, to save space and reduce clutter // Their names must include a "(" character char* noYearDbs[] = { "hg19", "hg38", "mm39", "mm10" }; + // on an assembly hub the organism, the freezeName (the hub's genome description) and the + // db name are all supplied by the hub, so escape them before they go in the page if ( stringArrayIx(database, noYearDbs, ArraySize(noYearDbs)) != -1 ) { // freezeName is e.g. "Feb. 2009 (GRCh37/hg19)" char *afterParen = skipBeyondDelimit(freezeName, '('); afterParen--; // move back one char - hPrintf("%s %s on %s %s", organization, browserName, organism, afterParen); + hPrintf("%s %s on %s %s", organization, browserName, htmlEncode(organism), + htmlEncode(afterParen)); } else if (startsWith("zoo",database) ) { hPrintf("%s %s on %s June 2002 Assembly %s target1", - organization, browserName, organism, freezeName); + organization, browserName, htmlEncode(organism), htmlEncode(freezeName)); } else { if (sameString(organism, "Archaea")) { hPrintf("%s %s on Archaeon %s Assembly", - organization, browserName, freezeName); + organization, browserName, htmlEncode(freezeName)); } else { if (stringIn(database, freezeName)) hPrintf("%s %s on %s %s", - organization, browserName, organism, freezeName); + organization, browserName, htmlEncode(organism), htmlEncode(freezeName)); else hPrintf("%s %s on %s %s (%s)", - organization, browserName, trackHubSkipHubName(organism), freezeName, trackHubSkipHubName(database)); + organization, browserName, htmlEncode(trackHubSkipHubName(organism)), + htmlEncode(freezeName), htmlEncode(trackHubSkipHubName(database))); } } hPrintf("</B></SPAN>"); //hPrintf("<span target=_blank title='Show details about this assembly' id='gatewayLink'>" //"<a href='hgGateway?hgsid=%s'>Assembly Info</a></span>", cartSessionId(cart)); printDatabaseInfoHtml(database); // Disable recommended track set panel when changing tracks, session, database char *sessionLabel = cartOptionalString(cart, hgsOtherUserSessionLabel); char *oldDb = hashFindVal(oldVars, "db"); if (sessionLabel) { if (defaultTracks || hideAll || hideTracks || @@ -10175,84 +10179,93 @@ jsOnEventByIdF("click", idText, "return vis.toggleForGroup(this, '%s');", group->name); if (isHubTrack(group->name)) { if (strstr(group->label, "Collections")) { safef(idText, sizeof idText, "%s_edit", group->name); hPrintf("<input name=\"hubEditButton\" id='%s'" " type=\"button\" value=\"edit\">\n", idText); jsOnEventByIdF("click", idText, "document.editHubForm.submit();return true;"); } } - hPrintf("</td><td style='text-align:center; width:90%%;'>\n<B>%s</B>", group->label); + // group->label for a hub group is built from the hub shortLabel and the hub's + // groups.txt label, both supplied by the hub, so escape it + hPrintf("</td><td style='text-align:center; width:90%%;'>\n<B>%s</B>", htmlEncode(group->label)); char *hubName = hubNameFromGroupName(group->name); struct trackHub *hub = grabHashedHub(hubName); if (hub && hub->url) { puts(" "); char infoText[10000]; if (startsWith("QuickLift", group->label)) safef(infoText, sizeof infoText, "This is a QuickLift track group that contains \ tracks that are annotations on %s that have been lifted to this \ assembly, along with a track (Alignment Differences) that shows \ mismatches and indels between %s and this assembly."\ , hub->defaultDb, hub->defaultDb); else safef(infoText, sizeof infoText, "A track hub is a list of tracks produced and hosted by external data providers. The UCSC browser group is not responsible for them. This hub is loaded from %s", hub->url); printInfoIconColor(infoText, "white"); } hPrintf("</td><td style='text-align:right;'>\n"); if (hubName) { if (cfgOptionBooleanDefault("groupDropdown", FALSE) && hub && hub->genomeList && hub->genomeList->next) { puts("<span style='font-size:13px'>Genomes: </span><select style='width:7em' name='db'>"); for (struct trackHubGenome *thg = hub->genomeList; thg != NULL; thg = thg->next) { if (!sameWord(thg->name, database)) - printf("<option value='%s'>%s</option>\n", thg->name, thg->name); + { + // hub genome names come from the hub, so encode them + char *escName = htmlEncode(thg->name); + printf("<option value='%s'>%s</option>\n", escName, escName); + } } puts("</select>"); } // visibility: hidden means that the element takes up space so the center alignment is not disturbed. if ((hub != NULL) && !startsWith("QuickLift", group->label)) { if (hub->descriptionUrl == NULL) { hPrintf("<a title='The track hub authors have not provided a descriptionUrl with background " "information about this track hub. "); if (hub->email) - hPrintf("The authors can be reached at %s. ", hub->email); + // hub-supplied, so encode it + hPrintf("The authors can be reached at %s. ", htmlEncode(hub->email)); hPrintf("This link leads to our documentation page about the descriptionUrl statement in hub.txt. "); hPrintf("' href='../goldenPath/help/hgTrackHubHelp.html#hub.txt' " "style='color:#FFF; font-size: 13px;' target=_blank>No Info</a>"); } else { hPrintf("<a title='Link to documentation about this track hub, provided by the track hub authors (not UCSC). "); if (hub->email) - hPrintf("The authors can be reached at %s", hub->email); + // hub-supplied, so encode it + hPrintf("The authors can be reached at %s", htmlEncode(hub->email)); hPrintf("' href='%s' " - "style='color:#FFF; font-size: 13px;' target=_blank>Info</a>", hub->descriptionUrl); + "style='color:#FFF; font-size: 13px;' target=_blank>Info</a>", + htmlEncode(hub->descriptionUrl)); } hPrintf(" "); } } hPrintf("<button type='button' class=\"hgtButtonHideGroup\" data-group-name=\"%s\" " "title='Hide all tracks in this group'>Hide group</button> ", group->name); // The BLAT Results group gets a "Delete all" button that removes every BLAT result track // at once, so users are not stuck deleting accumulated results one by one. if (sameString(group->name, "blat")) {