983b7eff4b1c516c9cb7bb56cc1399216a127d51 max Wed Aug 19 04:02:39 2026 -0700 address v503 preview1 code review (#38141): escaping and oauth fixes Fixes the six items Brian raised reviewing the XSS sweep (#38057) and the BLAT-results group work (#38086): - hgGenome/configure.c, hgPal.c: drop htmlEncode() on cartWebStart title args; cartWebStart already escapes the title, so this was double-escaping. - hgSession.c doReSaveSession: htmlEncode the user name and pass the encoded name to getSessionLink (same fix already applied at line 1544). - hgUserSuggestion.c printInvalidForm: cgiEncode the five cart values echoed into the mailto: href (reachable on the robot/captcha path). - hgSearch.c: cgiEncode db for the hgTracks URL query parameter instead of reusing the JSON-escaped copy meant for the JS string literal. - hgLogin.c oauthReturn: clone oauth_provider before cartRemove frees it, so the later oauthFetchIdentity call is not a read-after-free. - customFactory.c checkGroup: only accept group=blat when blatResultsGroup is on, matching hgTracks; otherwise the group is never created and the track would orphan into 'other'. refs #38141, refs #38057, refs #38086 diff --git src/hg/hgLogin/hgLogin.c src/hg/hgLogin/hgLogin.c index 558997735e5..7fe4b2d549b 100644 --- src/hg/hgLogin/hgLogin.c +++ src/hg/hgLogin/hgLogin.c @@ -2314,31 +2314,32 @@ { freez(&errMsg); errMsg = cloneString("Could not start social login. Please try again."); displayLoginPage(conn); return; } jsInlineF("window.location = '%s';\n", url); } void oauthReturn(struct sqlConnection *conn) /* Handle the provider's redirect back to us: verify state, exchange the code for the * user's identity, and resolve/auto-link the account. */ { char *state = cgiUsualString("state", ""); char *savedState = cartUsualString(cart, "oauth_state", ""); -char *provider = cartUsualString(cart, "oauth_provider", ""); +// clone this: cartRemove below frees the cart's copy, but we still use provider afterward +char *provider = cloneString(cartUsualString(cart, "oauth_provider", "")); // Validate the anti-CSRF state before consuming any cart state or acting on an error param. A // stray code/error link (a re-opened redirect, or a crafted hgLogin?error=...) must not be able to // consume the state nonce of a login in flight, so check first and only then clear the flow. A // compliant provider echoes state on an error return too (RFC 6749 4.1.2.1), and we always send it. if (isEmpty(state) || isEmpty(savedState) || differentString(state, savedState)) { freez(&errMsg); errMsg = cloneString("Your login session expired or was invalid. Please try again."); displayLoginPage(conn); return; } cartRemove(cart, "oauth_state"); // one-time use cartRemove(cart, "oauth_provider"); // end the flow so a later code/error param can't re-enter