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/hgPhyloPlace/phyloPlace.c src/hg/hgPhyloPlace/phyloPlace.c index f68ba78631e..d18a38cbb66 100644 --- src/hg/hgPhyloPlace/phyloPlace.c +++ src/hg/hgPhyloPlace/phyloPlace.c @@ -2004,31 +2004,31 @@ char *refAcc, char *db, int subtreeSize) /* Show a table with composition & alignment stats for each sequence that passed basic QC. */ { if (seqInfoList) { puts("<table class='seqSummary'>"); boolean gotClades = FALSE, gotLineages = FALSE; lookForCladesAndLineages(ur->samplePlacements, &gotClades, &gotLineages); printSummaryHeader(isFasta, gotClades, gotLineages, refAcc, db); puts("<tbody>"); struct dyString *dy = dyStringNew(0); struct seqInfo *si; for (si = seqInfoList; si != NULL; si = si->next) { puts("<tr>"); - printf("<th>%s</td>", replaceChars(si->seq->name, "|", " | ")); + printf("<th>%s</td>", htmlEncode(replaceChars(si->seq->name, "|", " | "))); // uploaded seq name, escape (XSS) if (isFasta) { if (si->nCountStart || si->nCountEnd) { int effectiveLength = si->seq->size - (si->nCountStart + si->nCountEnd); dyStringClear(dy); dyStringPrintf(dy, "%d ", effectiveLength); appendExcludingNs(dy, si); dyStringPrintf(dy, " (original size %d)", si->seq->size); printf("<td class='%s'>%d", qcClassForLength(effectiveLength), effectiveLength); printTooltip(dy->string); printf("</td>"); } else printf("<td class='%s'>%d</td>", qcClassForLength(si->seq->size), si->seq->size);