f759bf663debc22e6015c6c38c22f922bfbdf45b braney Fri Aug 21 10:01:02 2026 -0700 lib, cgilib: sanitize description HTML where it comes in, refs #38126 A track hub's track description, a custom track's documentation, and an assembly hub's genome description are all written by somebody else and were stored and printed as they arrived. Run each through htmlSanitize() at the point it is read, so that everything downstream sees text we are willing to print. Sanitizing on the way in is the only practical place: printTrackHtml() alone has more than a hundred callers, and hgTrackUi, hui.c, hgGene, hgGtexTrackSettings and hgTables all print tdb->html directly. The five places are trackHubAddOneDescription(), customTrack.c where it used to call jsStripJavascript(), the htmlUrl fetch in customFactory.c, hgPositionsHelpHtmlCart() and hAssemblyDescription(). In the last two, only the branch that fetches over the network is touched. The branch that reads a local file is left as it is, because those are our own description.html files. trackHubAddOneDescription() keeps its old shape. The fetch moves into a helper so that trackHubDescriptionRemovals() can hand hubCheck the list of things the filter takes out. diff --git src/hg/lib/trackHub.c src/hg/lib/trackHub.c index a37ea145888..bf24b125c45 100644 --- src/hg/lib/trackHub.c +++ src/hg/lib/trackHub.c @@ -15,30 +15,31 @@ * // do something with tdbList * trackHubClose(&hub); * Note that the tdbList returned does not have the parent/subtrack pointers set. * It is just a simple list of tracks, not a tree. */ #include "common.h" #include "linefile.h" #include "hash.h" #include "options.h" #include "udc.h" #include "ra.h" #include "filePath.h" #include "htmlPage.h" #include "trackDb.h" +#include "htmlSanitize.h" #include "trackHub.h" #include "errCatch.h" #include "hgBam.h" #include "bigWig.h" #include "bigBed.h" #include "barChartUi.h" #include "hdb.h" #include "chromInfo.h" #include "grp.h" #include "twoBit.h" #include "dbDb.h" #include "net.h" #include "bbiFile.h" #include "bPlusTree.h" #include "hgFind.h" @@ -1301,49 +1302,70 @@ } return NULL; } void trackHubAddGroupName(char *hubName, struct trackDb *tdbList) /* Add group tag that references the hubs symbolic name. */ { struct trackDb *tdb; for (tdb = tdbList; tdb != NULL; tdb = tdb->next) { tdb->grp = cloneString(hubName); hashReplace(tdb->settingsHash, "group", tdb->grp); } } -void trackHubAddOneDescription(char *trackDbFile, struct trackDb *tdb) -/* Fetch tdb->track's html description and store in tdb->html. */ +static char *trackHubDescriptionText(char *trackDbFile, struct trackDb *tdb) +/* Fetch the text of tdb->track's html description page, or NULL if it has none. */ { /* html setting should always be set because we set it at load time */ char *htmlName = trackDbSetting(tdb, "html"); if (htmlName == NULL) - return; + return NULL; char *simpleName = hubConnectSkipHubPrefix(htmlName); char *url = trackHubRelativeUrl(trackDbFile, simpleName); char buffer[10*1024]; char *fixedUrl = url; if (!endsWith(url, ".html")) { safef(buffer, sizeof buffer, "%s.html", url); fixedUrl = buffer; } -tdb->html = udcFileReadAllIfExists(fixedUrl, NULL, 0, NULL); +char *html = udcFileReadAllIfExists(fixedUrl, NULL, 0, NULL); freez(&url); +return html; +} + +void trackHubAddOneDescription(char *trackDbFile, struct trackDb *tdb) +/* Fetch tdb->track's html description and store in tdb->html. */ +{ +char *html = trackHubDescriptionText(trackDbFile, tdb); +tdb->html = htmlSanitize(html); +freeMem(html); +} + +struct slName *trackHubDescriptionRemovals(char *trackDbFile, struct trackDb *tdb) +/* Return a list of messages naming the parts of tdb's description page that we do not + * print, or NULL if we print all of it. */ +{ +char *html = trackHubDescriptionText(trackDbFile, tdb); +struct slName *removed = NULL; +char *clean = htmlSanitizeReport(html, &removed); +freeMem(html); +freeMem(clean); +return removed; } void trackHubAddDescription(char *trackDbFile, struct trackDb *tdb) /* Fetch tdb->track's html description (or nearest ancestor's non-empty description) * and store in tdb->html. */ { trackHubAddOneDescription(trackDbFile, tdb); if (isEmpty(tdb->html)) { struct trackDb *parent; for (parent = tdb->parent; isEmpty(tdb->html) && parent != NULL; parent = parent->parent) { trackHubAddOneDescription(trackDbFile, parent); if (isNotEmpty(parent->html)) tdb->html = cloneString(parent->html);