This program is a live‑streaming platform with seven or eight domains, including multiple subdomains. Since the platform has already been tested globally by security researchers for more than two years, I knew it would be inefficient to test everything. Instead, I focused on the interesting parts. I needed to deeply understand the program's implementation logic, user features, and developer documentation.

I started with user functionality. After spending some time understanding the permission system for streamers, I discovered that even if a streamer sets their video clips to private, the GraphQL API for retrieving clips still exposes them. By simply modifying the owner_id parameter to the streamer's ID, it was possible to access another user's private clips — and the IDs were enumerable. This issue existed across several different endpoints: one captured from the mobile app, one from the web creator dashboard, one documented in the API docs, and another on a subdomain. All of them allowed access to private clips.

After reporting these smaller issues, I wasn't satisfied. I began studying the Single Sign‑On (SSO) mechanisms described in the developer documentation. There are six SSO methods in total. The purpose of SSO is to allow users to log in or use third‑party services conveniently. The authorization page requires the user to click "Authorize," and it displays the permissions being granted. The user can choose to approve or deny.

Because authorization requires only a single click, the page was vulnerable to a double‑click hijacking attack. The attack works like this: the victim opens a webpage that asks them to double‑click a button to prove they are not a robot. The first click closes the fake prompt, revealing the real authorization page underneath. The second click lands on the "Authorize" button, granting access before the victim can react. The attacker then obtains the victim's token and can take over the account. For details, see: https://www.evil.blog/2024/12/doubleclickjacking-what.html. I reported the issue, but unfortunately it was a duplicate — someone else had reported it months earlier, so it didn't count as a valid finding.

Soon after, I noticed that the token obtained through SSO had the exact same format as the token used by users on the main site. When users operate on the main site, the API endpoint is gql.target.com/xxx, while tokens obtained through SSO are intended for api.target.com/xxx (where "target" represents the platform). I quickly created an SSO authorization link using my own client ID from the developer documentation, requesting only permission to read the user's bio (which is already public). After the victim authorized it, I attempted to modify their profile using the token. If it worked, it could lead to full account takeover. But when I sent requests to gql.target.com/xxx, the server responded that the token was invalid. Was that the end of it?

Is it over or not?

I thought so — until I discovered a new subdomain during another round of subdomain enumeration: tv.target.com. I found that this domain is used by the platform's TV devices, which rely on the device‑login SSO flow (one of the six SSO methods). The process works like this: using my own third‑party client ID, I request id.target.tv/oauth2/device, which returns an authorization URL and a device code. The user opens the authorization URL and clicks "Authorize," and then the third party exchanges the device code at id.target.tv/oauth2/token to obtain the user's token.

After logging in, I didn't see many available features. I checked API after API pointing to gql.target.com, but nothing seemed interesting. Wait — all of these APIs were calling from gql.target.com. But wasn't the token obtained through my third‑party client ID supposed to be invalid for gql.target.com? Why could the Target TV client do it? Then I realized: the Target TV client is a first‑party application. It gets special treatment.

Normally, after a user authorizes an SSO request, the token is sent back to the third party via redirect, and others cannot get token. But the device‑login flow does not require redirects — the third party directly receives the token after the user authorizes. That was the key.

After piecing everything together, I used the first‑party "target TV" client ID to initiate a device‑login flow. I requested permissions that only involved public user information. Since users needed to use the third‑party service and the permissions didn't look sensitive, they would click "Authorize." Once I obtained the victim's token, I called gql.target.com APIs — and it worked. I could modify the user's bio, change their email, delete videos, and even update payout information. This was full account takeover.😄

I then tested the "target developer" first‑party client ID and found that it could also obtain tokens and perform privilege escalation. I immediately reported the vulnerability.

In the end, I submitted the vulnerability and received a total bounty of 1,400 USD.

Thank you for reading.