156dbcfc96c9a4a5eba481f8d979700b0ca1024e
galt
  Mon Feb 3 06:28:18 2025 -0800
Fixing security concern in hgEncodeVocab. fixes #287. Note that actual full cleanup by removing the unneeded encode/cv.ra from trackDb files has not been done yet., and making the code tolerate its presence or absence in the trackDb.ra files, at the start of the controlledVocabulary setting.

diff --git src/hg/lib/hui.c src/hg/lib/hui.c
index 5d1c4bbeae8..8a89d8db1ea 100644
--- src/hg/lib/hui.c
+++ src/hg/lib/hui.c
@@ -174,47 +174,38 @@
     // until it's implemented
     {
     char *tbOff = trackDbSetting(tdb, "tableBrowser");
     if (isNotEmpty(tbOff) && sameString(nextWord(&tbOff), "off"))
 	return FALSE;
     char *hint = " title='Open data format (table schema) in new window'";
     if (label == NULL)
 	label = " View data format";
     struct trackDb *topLevel = trackDbTopLevelSelfOrParent(tdb);
     printf(SCHEMA_LINKED, db, topLevel->grp, topLevel->track, tdb->table, hint, label);
     return TRUE;
     }
 return FALSE;
 }
 
-char *wgEncodeVocabLink(char *file,char *term,char *value,char *title, char *label,char *suffix)
+char *wgEncodeVocabLink(char *term,char *value,char *title, char *label,char *suffix)
 // returns allocated string of HTML link to controlled vocabulary term
 {
-#define VOCAB_LINK_WITH_FILE "<A HREF='hgEncodeVocab?ra=%s&%s=\"%s\"' title='%s details' " \
-			 "class='cv' TARGET=ucscVocab>%s</A>"
 #define VOCAB_LINK "<A HREF='hgEncodeVocab?%s=\"%s\"' title='%s details' class='cv' " \
 	       "TARGET=ucscVocab>%s</A>"
 struct dyString *dyLink = NULL;
 char *encTerm = cgiEncode(term);
 char *encValue = cgiEncode(value);
-if (file != NULL)
-    {
-    char *encFile = cgiEncode(file);
-    dyLink = dyStringCreate(VOCAB_LINK_WITH_FILE,encFile,encTerm,encValue,title,label);
-    freeMem(encFile);
-    }
-else
 dyLink = dyStringCreate(VOCAB_LINK,encTerm,encValue,title,label);
 if (suffix != NULL)
     dyStringAppend(dyLink,suffix);  // Don't encode since this may contain HTML
 
 freeMem(encTerm);
 freeMem(encValue);
 return dyStringCannibalize(&dyLink);
 }
 
 char *pairsAsHtmlTable( struct slPair *pairs, struct trackDb *tdb, boolean showLongLabel,boolean showShortLabel)
 /* Return a string which is an HTML table of the tags for this track. */
 {
 if (pairs == NULL)
     return "";
 
@@ -283,36 +274,36 @@
 		dyStringAppend(dyTable,"<BR>");
 	    slNameFree(&file);
 	    }
 	dyStringAppend(dyTable,"</td></tr>");
 	}
     else
 	{                                           // Don't bother with tableName
 	if (cvTermTypes && differentString(mdbVar->var,MDB_VAR_TABLENAME))
 	    {
 	    struct hash *cvTerm = hashFindVal(cvTermTypes,mdbVar->var);
 	    if (cvTerm != NULL) // even if cvTerm isn't used,
 		{               // it proves that it exists and a link is desirable
 		if (!cvTermIsHidden(mdbVar->var))
 		    {
 		    char *label = (char *)cvLabel(NULL,mdbVar->var);
-		    char *linkOfType = wgEncodeVocabLink(NULL,CV_TYPE,mdbVar->var,label,
+		    char *linkOfType = wgEncodeVocabLink(CV_TYPE,mdbVar->var,label,
 							   label,NULL);
 		    if (cvTermIsCvDefined(mdbVar->var))
 			{
 			label = (char *)cvLabel(mdbVar->var,mdbVar->val);
-			char *linkOfTerm = wgEncodeVocabLink(NULL,CV_TERM,mdbVar->val,label,
+			char *linkOfTerm = wgEncodeVocabLink(CV_TERM,mdbVar->val,label,
 							       label,NULL);
 			dyStringPrintf(dyTable,"<tr valign='bottom'><td align='right' nowrap>"
 					       "<i>%s:</i></td><td nowrap>%s</td></tr>",
 					       linkOfType,linkOfTerm);
 			freeMem(linkOfTerm);
 			}
 		    else
 			dyStringPrintf(dyTable,"<tr valign='bottom'><td align='right' nowrap>"
 					       "<i>%s:</i></td><td nowrap>%s</td></tr>",
 					       linkOfType,mdbVar->val);
 		    freeMem(linkOfType);
 		    continue;
 		    }
 		}
 	    }
@@ -8572,44 +8563,44 @@
 char *words[SMALLBUF];
 int count;
 if ((count = chopByWhite(cloneString(vocab), words, SMALLBUF)) <= 1)
     return cloneString(label);
 
 
 char *suffix = NULL;
 char *rootLabel = labelRoot(label, &suffix);
 
 boolean found = FALSE;
 int ix;
 for (ix=1;ix<count && !found;ix++)
     {
     if (sameString(vocabType,words[ix])) // controlledVocabulary setting matches tag
         {                               // so all labels are linked
-        char *link = wgEncodeVocabLink(words[0],"term",words[ix],rootLabel,rootLabel,suffix);
+        char *link = wgEncodeVocabLink("term",words[ix],rootLabel,rootLabel,suffix);
         return link;
         }
     else if (countChars(words[ix],'=') == 1 && childTdb != NULL)
             // The name of a trackDb setting follows and will be the controlled vocab term
         {
         strSwapChar(words[ix],'=',0);
         if (sameString(vocabType,words[ix]))  // tags match, but search for term
             {
             char * cvSetting = words[ix] + strlen(words[ix]) + 1;
             const char * cvTerm = metadataFindValue(childTdb,cvSetting);
             if (cvTerm != NULL)
                 {
-                char *link = wgEncodeVocabLink(words[0],
+                char *link = wgEncodeVocabLink(
                                     (sameWord(cvSetting,"antibody") ?  "target" : "term"),
                                     (char *)cvTerm,(char *)cvTerm,rootLabel,suffix);
                 return link;
                 }
             }
         }
     }
 freeMem(words[0]);
 freeMem(rootLabel);
 return cloneString(label);
 }
 
 #define PM_BUTTON_UC "<IMG height=18 width=18 id='%s' src='../images/%s'>"
 #define PM_BUTTON_UC_JS "return (matSetMatrixCheckBoxes(%s%s%s%s%s%s) == false);" 
 #define PM_MAKE_BUTTON_UC(s1,s2,s3,s4,s5,s6,name,img) \
@@ -8939,33 +8930,33 @@
         mdbVar = members->groupTag;
         break;
         }
     else if (startsWithWordByDelimiter(members->groupTag,'=',words[ix]))
         {
         mdbVar = words[ix] + strlen(members->groupTag) + 1;
         break;
         }
     }
 if (mdbVar == NULL)
     {
     freeMem(vocab);
     return cloneString(members->groupTitle);
     }
 
-#define VOCAB_MULTILINK_BEG "<A HREF='hgEncodeVocab?ra=%s&%s=\""
+#define VOCAB_MULTILINK_BEG "<A HREF='hgEncodeVocab?%s=\""
 #define VOCAB_MULTILINK_END "\"' title='Click for details of each %s' TARGET=ucscVocab>%s</A>"
-struct dyString *dyLink = dyStringCreate(VOCAB_MULTILINK_BEG,vocab,
+struct dyString *dyLink = dyStringCreate(VOCAB_MULTILINK_BEG,
                                          (sameWord(mdbVar,"antibody")?"target":"term"));
 
 // Now build the comma delimited string of mdb vals (all have same mdb var)
 boolean first = TRUE;
 for (ix=0;ix<members->count;ix++)
     {
     if (members->subtrackList[ix] != NULL && members->subtrackList[ix]->val != NULL)
         {
         struct trackDb *childTdb = members->subtrackList[ix]->val;
         (void)metadataForTable(db,childTdb,NULL); // Makes sure this has been populated
         const char * mdbVal = metadataFindValue(childTdb,mdbVar); // one for each is enough
         if (mdbVal != NULL)
             {
             if (!first)
                 dyStringAppendC(dyLink,',');