56fec2823d2419eb9395bed6f2b56dec2c1daceb
max
  Fri Aug 28 02:02:18 2026 -0700
Escape nodeName in variantPathPrint (XSS), found by automated code review

htmlEncode vpn->nodeName before printing in variantPathPrint() to close
XSS gap. The node name can be a user-uploaded sample ID (FASTA/VCF),
making this a reachable vulnerability of the same class the parent commit
closes in other spots.

diff --git src/hg/hgPhyloPlace/phyloPlace.c src/hg/hgPhyloPlace/phyloPlace.c
index c12f47b7476..ec370502c96 100644
--- src/hg/hgPhyloPlace/phyloPlace.c
+++ src/hg/hgPhyloPlace/phyloPlace.c
@@ -805,31 +805,31 @@
 if (startsWith(USHER_NODE_PREFIX, nodeName))
     nodeName += strlen(USHER_NODE_PREFIX);
 return isAllDigits(nodeName) && (minNewNode <= 0 || (atoi(nodeName) < minNewNode));
 }
 
 static void variantPathPrint(struct variantPathNode *variantPath)
 /* Print out a variantPath; print nodeName only if non-numeric
  * (i.e. a sample ID not internal node) */
 {
 struct variantPathNode *vpn;
 for (vpn = variantPath;  vpn != NULL;  vpn = vpn->next)
     {
     if (vpn != variantPath)
         printf(" > ");
     if (!isInternalNodeName(vpn->nodeName, 0))
-        printf("%s: ", vpn->nodeName);
+        printf("%s: ", htmlEncode(vpn->nodeName));
     struct singleNucChange *snc;
     for (snc = vpn->sncList;  snc != NULL;  snc = snc->next)
         {
         if (snc != vpn->sncList)
             printf(", ");
         printf("%c%d%c", snc->parBase, snc->chromStart+1, snc->newBase);
         }
     }
 }
 
 static void displayVariantPath(struct variantPathNode *variantPath, char *sampleId)
 /* Display mutations on the path to this sample. */
 {
 printf("<p>Mutations along the path from the root of the phylogenetic tree to %s:\n",
        htmlEncode(sampleId)); // uploaded sample name, escape (XSS)