a1d7c07c50f1d895337de121680ea672b261c058 max Mon Aug 17 02:26:36 2026 -0700 escape reflected/echoed user input across several CGIs (XSS), refs #38057 Route user-, DB- and hub-derived values through htmlEncode (HTML/attribute text), cgiEncode (values composed into URLs), jsonStringEscape (values placed in a JS string literal inside an inline script) or, for hgMirror, the existing mustBeClean sanitizer. Covers hgHubConnect, hgUserSuggestion, hgLiftOver, hgBlat, hgc pubs, hgVisiGene, hgSession, hgTrackUi, hgGenome, phyloPng, hgFileSearch, hgLinkIn, hgPal, hui, hgPhyloPlace, hgMirror, hgCustom and hgSearch. diff --git src/hg/hgGenome/configure.c src/hg/hgGenome/configure.c index 97f0fb9b7e7..ef968519047 100644 --- src/hg/hgGenome/configure.c +++ src/hg/hgGenome/configure.c @@ -1,157 +1,158 @@ /* Copyright (C) 2011 The Regents of the University of California * See kent/LICENSE or http://genome.ucsc.edu/license/ for licensing information. */ #include "common.h" +#include "htmshell.h" #include "hash.h" #include "jksql.h" #include "hCommon.h" #include "cart.h" #include "cheapcgi.h" #include "chromGraph.h" #include "web.h" #include "hPrint.h" #include "hui.h" #include "hgGenome.h" void makeNumMenu(char *varName, int minVal, int maxVal, int defaultVal) /* Make a drop down menu with a limited number of numerical choices. */ { int choiceCount = maxVal - minVal + 1; int i; printf("<SELECT NAME=\"%s\">\n", varName); for (i=0; i<choiceCount; ++i) { int choice = i + minVal; char *selString = ((choice == defaultVal) ? " SELECTED" : ""); hPrintf("<OPTION%s>%d</OPTION>\n", selString, choice); } printf("</SELECT>\n"); } char *chromLayouts[] = { layTwoPerLine, layOnePerLine, layAllOneLine, }; void configurePage() /* Put up configuration page. */ { cartWebStart(cart, database, "Configure Genome Graphs"); hPrintf("<FORM ACTION=\"../cgi-bin/hgGenome\" METHOD=GET>\n"); cartSaveSession(cart); hPrintf("<TABLE>\n"); hPrintf("<TR>\n"); hPrintf("<TD>\n"); hPrintf("image width: "); cgiMakeIntVar(hggImageWidth, cartUsualInt(cart, hggImageWidth, hgDefaultPixWidth), 4); hPrintf("</TD>\n"); hPrintf("<TD>\n"); hPrintf("graph height: "); cgiMakeIntVar(hggGraphHeight, graphHeight(), 3); hPrintf("</TD>\n"); hPrintf("<TD>\n"); hPrintf(" graphs per line: "); makeNumMenu(hggGraphsPerLine, minGraphsPerLine, maxGraphsPerLine, graphsPerLine()); hPrintf("</TD>\n"); hPrintf("<TD>\n"); hPrintf(" lines of graphs: "); makeNumMenu(hggLinesOfGraphs, minLinesOfGraphs, maxLinesOfGraphs, linesOfGraphs()); hPrintf("</TD>\n"); hPrintf("</TR>\n"); hPrintf("</TABLE>\n"); hPrintf("<TABLE><TR><TD>\n"); hPrintf("chromosome layout: "); cgiMakeDropList(hggChromLayout, chromLayouts, ArraySize(chromLayouts), chromLayout()); hPrintf("</TD></TR></TABLE>\n"); hPrintf("<TABLE><TR><TD>\n"); hPrintf("numerical labels: "); cartMakeCheckBox(cart, hggLabels, TRUE); hPrintf(" <I>Label axis on left for first graph and on right for last graph</I>"); hPrintf("</TD></TR></TABLE>\n"); hPrintf("<TABLE><TR><TD>\n"); hPrintf("highlight missing: "); cartMakeCheckBox(cart, hggYellowMissing, FALSE); hPrintf(" <I>Highlight background in yellow/gray if there is missing data in first graph</I>"); hPrintf("</TD></TR></TABLE>\n"); hPrintf("<TABLE><TR><TD>\n"); hPrintf("region padding: "); cgiMakeIntVar(hggRegionPad, regionPad(), 6); hPrintf(" <I>Number of bases to add to either side of regions over threshold</I>"); hPrintf("</TD></TR></TABLE>\n"); hPrintf("<TABLE><TR><TD>\n"); cgiMakeButton("submit", "submit"); hPrintf("</TD></TR></TABLE>\n"); hPrintf("</TD>\n"); hPrintf("</FORM>\n"); webNewSection("Configure Graphs"); hPrintf("Click on the hyperlink by the graph name to configure it."); hTableStart(); hPrintf("<TR><TH>name</TH>"); hPrintf("<TH>description</TH></TR>"); struct slRef *ref; for (ref = ggList; ref != NULL; ref = ref->next) { struct genoGraph *gg = ref->val; /* Only show custom graphs, stand-alone DB graphs, and composite */ /* graphs. Don't show subGraphs part of a composite. */ if (gg->isSubGraph == FALSE) { char *tmp = cgiEncode(gg->name); hPrintf("<TR><TD><A HREF=\"../cgi-bin/hgGenome?%s&%s=on&g=%s\">", cartSidUrlString(cart), hggConfigureOne, tmp); freeMem(tmp); - hPrintf("%s</A></TD>", gg->shortLabel); - hPrintf("<TD>%s</TD></TR>\n", gg->longLabel); + hPrintf("%s</A></TD>", htmlEncode(gg->shortLabel)); // user graph label, escape (XSS) + hPrintf("<TD>%s</TD></TR>\n", htmlEncode(gg->longLabel)); } } hTableEnd(); cartWebEnd(); } void configureOnePage() /* Put up configuration for one graph. */ { /* Figure out which graph we're configuring. */ char *graphName = cartString(cart, "g"); struct genoGraph *gg = hashFindVal(ggHash, graphName); if (gg == NULL) { /* Warn/return rather than abort if have problems, so that * cartRemovePrefix(hggDo) is executed to keep us from error * loop forever... */ warn("Graph %s not found", graphName); return; } /* Put up web page with controls */ -cartWebStart(cart, database, "Configure %s", gg->shortLabel); +cartWebStart(cart, database, "Configure %s", htmlEncode(gg->shortLabel)); hPrintf("<FORM ACTION=\"../cgi-bin/hgGenome\" METHOD=GET>\n"); cartSaveSession(cart); cgiMakeHiddenVar(hggConfigure, "on"); struct chromGraphSettings *cgs = gg->settings; char varName[chromGraphVarNameMaxSize]; chromGraphVarName(gg->name, "minVal", varName); hPrintf("display min value: "); cartMakeIntVar(cart, varName, cgs->minVal, 5); chromGraphVarName(gg->name, "maxVal", varName); hPrintf(" max value: "); cartMakeIntVar(cart, varName, cgs->maxVal, 5); hPrintf("<BR>\n"); hPrintf("draw connecting lines between markers separated by up to "); chromGraphVarName(gg->name, "maxGapToFill", varName); cartMakeIntVar(cart, varName, cgs->maxGapToFill, 8); hPrintf(" bases."); hPrintf("<BR>\n"); cgiMakeButton("submit", "submit"); hPrintf("</FORM>\n"); cartWebEnd(); }