ae1b9adc9d85808683118f771703aeb8970306bf
braney
  Sat Aug 22 10:19:03 2026 -0700
hubApi: add X-Content-Type-Options: nosniff to responses, refs #38163

Set the nosniff header ahead of the Content-Type on every hubApi output
path (JSON, text, and html), so responses declare their type explicitly.

diff --git src/hg/hubApi/apiUtils.c src/hg/hubApi/apiUtils.c
index a288be641e7..7a482b0c1bd 100644
--- src/hg/hubApi/apiUtils.c
+++ src/hg/hubApi/apiUtils.c
@@ -8,30 +8,31 @@
 /* when measureTiming is used */
 static long processingStart = 0;
 
 void startProcessTiming()
 /* for measureTiming, beginning processing */
 {
 processingStart = clock1000();
 }
 
 void apiFinishOutput(int errorCode, char *errorString, struct jsonWrite *jw)
 /* finish json output, potential output an error code other than 200 */
 {
 /* this is the first time any output to stdout has taken place for
  * json output, therefore, start with the appropriate header.
  */
+puts("X-Content-Type-Options: nosniff");
 puts("Content-Type:application/json");
 /* potentially with an error code return in the header */
 if (errorCode)
     {
     char errString[2048];
     safef(errString, sizeof(errString), "Status: %d %s",errorCode,errorString);
     puts(errString);
     if (err429 == errorCode)
 	puts("Retry-After: 30");
     }
 else if (reachedMaxItems)
     {
     char errString[2048];
     safef(errString, sizeof(errString), "Status: %d %s",err206,err206Msg);
     puts(errString);
@@ -830,30 +831,31 @@
             1900+tm.tm_year, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min,
              tm.tm_sec);
         dyStringPrintf(textOutput, "%s\n", outString);
         safef(outString, sizeof(outString), "# downloadTimeStamp: %lld",
             (long long) timeNow);
         dyStringPrintf(textOutput, "%s\n", outString);
         }
     }
 
 dyStringPrintf(textOutput, "%s\n", lineOut);
 }
 
 void textFinishOutput()
 /* all done with text output, print it all out */
 {
+puts("X-Content-Type-Options: nosniff");
 puts("Content-Type:text/plain\n");
 printf("%s", dyStringCannibalize(&textOutput));
 }
 
 static char *thisHostName()
 /* Return this machine's own hostname via gethostname().  Unlike hHttpHost(),
  * which reflects the client-supplied HTTP_HOST/Host: header, this can't be
  * spoofed by the request and doesn't change depending on which round-robin
  * name (e.g. genome.ucsc.edu) the client used to reach this box -- using
  * hHttpHost() here made onGenomeRRMachine() misclassify RR machines reached
  * via the genome.ucsc.edu name, sending them into an infinite self-relay
  * loop. */
 {
 static char host[256];
 static boolean init = FALSE;