139e158c2b2817ea64048290f046105d25f97198
braney
  Tue Aug 18 11:15:51 2026 -0700
hgHubConnect: encode hub label and contact fields consistently, refs #38123

diff --git src/hg/hgHubConnect/hgHubConnect.c src/hg/hgHubConnect/hgHubConnect.c
index 65d37febc54..45270e54649 100644
--- src/hg/hgHubConnect/hgHubConnect.c
+++ src/hg/hgHubConnect/hgHubConnect.c
@@ -82,33 +82,34 @@
 
 
 static void ourCellStart()
 {
 fputs("<TD>", stdout);  // do not add a newline
 }
 
 static void ourCellEnd()
 {
 puts("</TD>");
 }
 
 static void ourPrintCellLink(char *str, char *url)
 {
 ourCellStart();
-printf("<A class=\"cv\" HREF=\"%s\" TARGET=_BLANK>\n", url);
+// every caller passes a hub label and a hub url, both text from a stranger, so escape
+printf("<A class=\"cv\" HREF=\"%s\" TARGET=_BLANK>\n", htmlEncode(url));
 if (str != NULL)
-    fputs(str, stdout); // do not add a newline -- was causing trailing blanks get copied in cut and paste 
+    fputs(htmlEncode(str), stdout); // do not add a newline -- was causing trailing blanks get copied in cut and paste 
 puts("</A>");
 ourCellEnd();
 }
 
 static void ourPrintCell(char *str)
 {
 ourCellStart();
 if (str != NULL)
     fputs(str, stdout); // do not add a newline -- was causing trailing blanks get copied in cut and paste 
 ourCellEnd();
 }
 
 static char *removeLastComma(char *string)
 {
 if (string != NULL)
@@ -363,31 +364,31 @@
 	safef(id, sizeof id, "hubClearButton%d", count);
 	// give people a chance to clear the error 
 	printf("<input name=\"hubClearButton\"  id='%s' "
 		"class=\"hubButton\" type=\"button\" value=\"Retry Hub\">"
 		, id);
 	jsOnEventByIdF("click", id,
 	    "document.resetHubForm.elements['hubCheckUrl'].value='%s';"
 	    "document.resetHubForm.submit(); return true;", javaScriptLiteralEncode(hub->hubUrl));
 	ourCellEnd();
 	}
     else if (hub->trackHub != NULL)
 	{
 	if (hub->trackHub->descriptionUrl != NULL)
 	    ourPrintCellLink(hub->trackHub->longLabel, hub->trackHub->descriptionUrl);
 	else
-	    ourPrintCell(hub->trackHub->longLabel);
+	    ourPrintCell(htmlEncode(hub->trackHub->longLabel));  // hub supplied
 	}
     else
 	ourPrintCell("");
 
 
     if (hub->trackHub != NULL)
 	printGenomes(hub->trackHub, count, !hubHasError);
     else
 	ourPrintCell("");
 
     puts("</tr>");
     }
 
 printf("</tbody></TABLE>\n");
 puts("</FORM>");
@@ -686,31 +687,31 @@
         }
 
     ourCellEnd();
     }
 else
     errAbort("cannot get id for hub with url %s\n", hubInfo->hubUrl);
 
 ourPrintCellLink(hubInfo->shortLabel, hubInfo->hubUrl);
 
 boolean hubHasNoError = isEmpty(hubInfo->errorMessage);
 if (hubHasNoError)
     {
     if (hubInfo->tableHasDescriptionField && !isEmpty(hubInfo->descriptionUrl))
         ourPrintCellLink(hubInfo->longLabel, hubInfo->descriptionUrl);
     else
-        ourPrintCell(hubInfo->longLabel);
+        ourPrintCell(htmlEncode(hubInfo->longLabel));  // hub supplied
     }
 else
     {
     ourCellStart();
     printf("<span class=\"hubError\">ERROR: %s </span>"
         "<a href=\"../goldenPath/help/hgTrackHubHelp.html#Debug\">Debug Help</a>", 
         hubInfo->errorMessage);
     safef(jsId, sizeof jsId, "hubClearButton%d", count);
     printf(
     "<input name=\"hubClearButton\" id='%s' "
             "class=\"hubButton\" type=\"button\" value=\"Retry Hub\">"
             , jsId);
     jsOnEventByIdF("click", jsId, 
         "document.resetHubForm.elements['hubCheckUrl'].value='%s';"
         "document.resetHubForm.submit();return true;", hubInfo->hubUrl);
@@ -1432,52 +1433,54 @@
 char *errorMessage;
 hubFindOrAddUrlInStatusTable(cart, hub->hubUrl, &errorMessage);
 
 // if there is an error message, we stay in hgHubConnect
 if (errorMessage != NULL)
     return 0;
 
 getDbAndGenome(cart, &database, &organism, oldVars);
 
 char headerText[1024];
 safef(headerText, sizeof(headerText), "Hub Connect Successful");
 cartWebStart(cart, NULL, "%s", headerText);
 
 struct trackHub *tHub = hub->trackHub;
 
-hPrintf("<P><B>Connected Hub: </B>%s</P>", tHub->shortLabel);
+// the labels, the email and the per genome organism and description all come out of the
+// hub's own text files, so escape them before printing
+hPrintf("<P><B>Connected Hub: </B>%s</P>", htmlEncode(tHub->shortLabel));
 
-hPrintf("<P><B>Hub Description:</B> %s</P>", tHub->longLabel);
-hPrintf("<P><B>Contact email:</B> <A HREF=\"mailto:%s\">%s</A>.</B> Use this contact for all data questions.</P>", tHub->email, tHub->email);
+hPrintf("<P><B>Hub Description:</B> %s</P>", htmlEncode(tHub->longLabel));
+hPrintf("<P><B>Contact email:</B> <A HREF=\"mailto:%s\">%s</A>.</B> Use this contact for all data questions.</P>", htmlEncode(tHub->email), htmlEncode(tHub->email));
 struct trackHubGenome *genomeList = tHub->genomeList;
 
 hPrintf("<P><B>Assemblies:</B> Select an assembly below to start browsing the tracks of this hub:<P>");
 
 hPrintf("<ul>");
 
 for(; genomeList; genomeList = genomeList->next)
     {
     char *desc = genomeList->description;
     if (desc==NULL)
         desc = hFreezeFromDb(genomeList->name);
 
     char *org = trackHubSkipHubName( genomeList->organism );
     if (org==NULL)
         org = trackHubSkipHubName(hOrganism(genomeList->name));
 
-    hPrintf("<li>Open: <A href=\"../cgi-bin/hgTracks?db=%s&%s&position=lastDbPos\">%s: %s</A></li>",genomeList->name, 
-        cartSidUrlString(cart), org, desc);
+    hPrintf("<li>Open: <A href=\"../cgi-bin/hgTracks?db=%s&%s&position=lastDbPos\">%s: %s</A></li>",
+        htmlEncode(genomeList->name), cartSidUrlString(cart), htmlEncode(org), htmlEncode(desc));
     }
 hPrintf("</ul>");
 
 hPrintf("<P><A href=\"./hgHubConnect#unlistedHubs\">Connect another hub</A> to add more tracks.</P>");
 
 hPrintf("<P><I>Hubs are created and maintained by external sources. UCSC is not responsible for their content and status.</I></P>");
 
 return 1;
 }
 
 static void doResetHub(struct cart *theCart)
 {
 char *url = cartOptionalString(cart, hgHubCheckUrl);
 
 if (url != NULL)