BOOK THIS SPACE FOR AD
ARTICLE ADLegal disclaimer: The information provided in this article has been carefully redacted and modified to prioritize the security of TikTok’s platform and its users. Details regarding specific vulnerabilities, technical methodologies, and potential exploitation vectors have been intentionally altered or omitted to prevent misuse. The content is presented solely for educational purposes to raise awareness about cybersecurity practices and does not advocate or condone any form of unauthorized access, exploitation, or malicious activity against any platform or system. Readers are advised to always adhere to ethical hacking guidelines, responsible disclosure policies, and applicable laws when conducting security research. The author and publisher disclaim all responsibility for any unlawful use of the information contained within this article. Violating the law can result in severe penalties, including legal action and prosecution.
Hi and welcome. I’ve been researching TikTok’s API for a few months (August 2023 — March 2024) and during this time, I’ve discovered multiple vulnerabilities ranging from medium to critical severity. In this article, I’ll mainly talk about the 3 TikTok account takeover vulnerabilities, but also try to cover some of the other ones as well for educational purposes. This article will be quite long and may be a bit complex, so allocating at least 15 minutes of your time without any distractions is recommended. Let’s dive in.
To fully understand the vulnerabilities I’m about to explain, we first need to understand TikTok’s recovery process. It is pretty common for users to lose access to their account, and that’s why TikTok implemented a recovery system which can help you get back into your account. No, I’m not talking about password reset through email or phone number. There’s another way to recover your account not many people know about — let me show you.
By clicking on the question mark, then clicking on “Recover your account”, you will be able to get into the account recovery interface. From here, you have a few options to search for your account. You can do that by username, phone number, email or Instagram username. There are a few more ways to look up the account which are not present in the TikTok app itself and only in TikTok’s API, but that doesn’t really matter, as our main focus will be on those 4 options. You can pick any option, but my favorite is searching by username as you don’t need any identifiable and potentially private information to obtain the results. Let’s look up the username “username” and see what it returns:
As you can see, the search for the account with username “username” returned information indicating there’s a linked phone number and email address — interesting.
My first though was, how does this work “under the hood?”. Which part of this process is responsible for supplying the information about the account? I wanted to see the details. That’s where Burp Suite came in, a handy tool which can let you see what you normally can’t. Unfortunately for me, new TikTok app versions were packed with SSL pinning protection which made it impossible to intercept what’s really going on, but thankfully, I had a script which helped me to remove the protection:
adb shell#inside adb shell
su
apk=$(pm path com.zhiliaoapp.musically | cut -d':' -f2)
app_dir=$(dirname $apk)
libsscronet=$app_dir/lib/arm64/libsscronet.so #for arm replace arm64 with arm
echo $libsscronet
#/data/app/~~MaV1k6AHxSX2VmtJHZXXZg==/com.zhiliaoapp.musically-qb3IhNrRlxGAHW93wN_haw==/lib/arm64/libsscronet.so
cp "$libsscronet" /sdcard/libsscronet.so
exit
exit
#outsite adb shell
adb pull /sdcard/libsscronet.so
This works for any version up to 31.5.3. Note that your device must be rooted in order for this to work. Shoutout to Eltion Musa for making the script.
Now that we’ve bypassed SSL pinning, it’s time to intercept the entire process and see what’s going on. Right after entering a username and clicking on “Next”, series of requests to the following endpoints are generated:
/*/*/tiktok_username//*/*/safe_verify/
/*/*/available_ways/
Parts of the endpoints were redacted for security reasons. Let me now explain what each endpoint does:
The first endpoint ending in /tiktok_username/ is responsible for supplying a special “not login token”This token is then passed to second endpoint ending in /safe_verify/. The purpose of the second endpoint is to compare this token with a device identifier which was assigned to your device when you first downloaded TikTok. If you were previously logged in the account you’re trying to recover (using the same device with the same identifier of course), chances are TikTok API will issue another token (let’s call it verify token) (since your device is recognized) which can be used in the third endpoint /available_ways/ along with the first not login token to reveal some more sensitive information about the account (e.g. masked email address, for example v*****l@gmail.com) and even help you to login with SMS verification code.The third and final endpoint is /available_ways/, which is used to display information about the account when valid token(s) are provided.Let’s start from the smallest things to the most critical ones. First of all, why in the world am I able to see what things are linked to any TikTok account? The app shows information such as if there’s an email or phone number linked, or even if there’s any third party platform like Facebook connected to the account. But when you look at the response from the API (endpoint /available_ways/), it’s worse:
{"data":{"avatar_url":"https://redacted.com/obj/eden-va2/ayvwzzhW/ljhwZthlaukjlkulzlp/default_user_avatar.png","email":"******@***.***","error_code":0,"has_email":true,"has_mobile":true,"has_oauth":false,"has_pwd":true,"is_ftc_user":false,"is_login":false,"is_most_device":false,"mobile":"******","oauth_platforms":null,"token":"","username":"******"},"message":"success"}=It shows the following information:if the account has linked email address (just like in app)if the account has linked phone number (just like in app)if the account has any external oauth platforms connectedif the account has set a password+ more unnecessary information that shouldn’t be public for the sake of user privacyLet’s shift focus to the /tiktok_username/ endpoint though, which generates the special “not login token”. Firstly I didn’t really think much of it — I just assumed this token was for the account lookup only. That was, until I was testing TikTok’s two factor authentication mechanism. To my surprise, when I entered username and correct password for my account which had 2-factor authentication enabled, the response contained the same parameter used in the account recovery process — that is, the not login token. Very weird, right? Why would TikTok use the not login token in the account recovery process where you only need to provide the account’s username and then use the same token for two factor authentication where you actually needed to enter a correct password to get to that step? Wait, so what is the not login token for? What functionality does it serve? If you’re getting lost already, I’ll explain.
Think of the not login token as some form of temporary session ID. The not login token is an unreadable string of random letters and numbers. It might be unreadable to you and me, but this string is very well understood by the backend. When this token is generated, it is tied to the account it was generated for. So, when you request account recovery for the account “username” and you receive the token, it’s saved in the backend and tied to the account “username”. When you enter a correct password and username for your account & you’ve enabled 2FA, the backend will generate this not login token as well, so you can use it to send the 2FA verification code and then login. So basically, the not login token is also tied to the phone number/email (if any are linked). This means that I can use this token to send verification codes to email/phone number which is linked to the account “username” without actually knowing the linked phone number/email. Also, the Not Login Token gives partial access to the account. This will prove to be a significant issue later on.
Now that we’ve explained some basics, let’s dive into the first account takeover vulnerability.
This is the simplest account takeover vulnerability that I’ve ever found. Back in 2023, long before I even knew bug bounty programs existed, I’ve been exploring TikTok’s older version for iOS on my old jailbroken iPhone for fun. I had no experience at all, so what I was basically doing was playing with random parameters, trying to remove some and add some — just basic stuff. One day, when I was trying the phone number SMS password reset functionality, I found something very interesting. When inserting a random 4 or 6-digit verification code, a request for password reset is generated, and the parameters look like this:
mobile=+12345678900&code=1111&mix_mode=0&password=Abcdefg123!Quite straightforward, right? When sending the request, the password reset was of course denied, because the code was invalid. The backend code had one crucial mistake though; when the entire “code” parameter was removed, the password reset for some reason went through. So basically, sending this:
mobile=+12345678900&mix_mode=0&password=Abcdefg123!resulted in the password being changed to Abcdefg123! for the TikTok account which had the linked number +12345678900. So there was a lack of validation for the presence of the “code” parameter which resulted in the vulnerability. There were two limitations though — you needed to know the entire phone number and you could only reset password for accounts which had a linked phone number.
Wait, remember when I talked about the not login token? How it’s tied to the phone number/email of the account in TikTok’s backend? Why not go back to the account recovery page, type username of the account on which you want to do the password reset, see if there’s a number linked, grab the not login token, insert that token parameter into the password reset request instead of the parameter “mobile” and see what happens? Bam, it worked! The password was changed, and the only thing I needed to know was the account username & I needed to make sure there was a linked phone number. I could take over any account which had a phone number linked to it!
This vulnerability was reported by other researchers very quickly as someone else has discovered this and spread it around like wildfire & it was fixed within a week of discovery.
Speaking of phone numbers, let’s talk about another vulnerability which I would classify as medium severity, before we move to the other 2 critical account takeovers.
When you have a TikTok account, chances are there’s a linked email, phone number or both which you own or have access to. These can help you to get back into your account if you forget your password, or you can get a verification code and login with that. Sometimes, you might want to unlink this phone number or email from the account for various reasons, usually when you want to add the same number/email to a different TikTok account. To unlink either the email or phone number, you need to verify your identity by requesting an OTP. If the OTP is correct, it removes the phone number or email from the account.
This was set up with good intent, to minimize chances for hackers to steal your account when they somehow get your password and log in. Yes, they might know the password, but they don’t know the OTP, as they don’t have access to your linked phone number or email address, and therefore cannot gain full control of the account, so as an owner, you have high chances of recovering it. The system is unfortunately flawed again, and the OTP (verification code) can be bypassed. Let me show you how:
When intercepting the mobile unlink process with Burp Suite, we can see the following requests being made:
A request to /*/*/send_code/ (used for sending the OTP)Then a request to /*/*/validate_code/ (used for validation of the verification code)
Finally, a request to /*/*/unbind/ is made to unlink the phone number
We will focus on the /validate_code/ endpoint. When you enter a correct OTP (verification code), this endpoint will give you a special verify token, which can be used to unlink the phone number (or email). The issue is that, for some reason, TikTok decided to implement the same verify token on other endpoints with different verification options. When going into account settings and setting up 2FA, TikTok usually asks you for the account password before turning the 2FA on. When you enter the correct password and intercept the request, the same verify token which would be generated by entering correct OTP in the mobile unlink process is generated when a correct account password is entered.
You can then use that token, pass it to the /unbind/ endpoint, and the phone number will be gone, just like that.
So if you’re an attacker and know the password, you can basically do a full account takeover because you can remove the phone number (or email) by using the token which was generated when you’ve entered the password (which you already know) at 2FA setup. Lol.
This issue was personally reported by me, but TikTok marked it as “duplicate”, said that they do not believe this would pose a security threat and simply closed the report. Later, I’ve learned from some of my connections that TikTok is aware of this issue, and is working on a fix. As of 2024, the vulnerability remains unpatched and no action was taken by TikTok to get this patched.
Remember when I explained the functionality of not login token? If you’re not sure, scroll back up to fully understand how it works. It will get complex from this point onwards, so read everything carefully if you want to understand this.
Changing email address on any TikTok account, globally
You read that right. I found a way to connect my email address to any TikTok account without access, no matter the country, number of followers, linked stuff, etc. ANY! Let’s dive in.
When I was exploring the email change functionality, it worked like this:
First, you sent a code to the email address which was already linked on the target account (/send_code/)Then, you entered the code, which gave you a verify token with permissions to change the email address (/email/verify/)Then, you entered the new email you wished to connect, along with the verify token, and clicked on send code, which sent an OTP to the new email address (/send_code/ + verify token param)Finally, you entered the correct OTP, which updated the email address of the account to the new one ( on endpoint /email/update/)So, what was wrong here? Looks secure, right?
On the first sight? Absolutely! However, there were few critical issues. Let’s go over them one by one:
Lack of check for the verify token at /email/update/ — this endpoint, which had the functionality for changing the email address, was not properly checking for the value of the verify token. This meant that I did not need to know the OTP for the currently linked email at all! Additionally, even though sessionid was needed for this endpoint, not login token could be used instead. This meant I had the ability to change the email address without having a valid session (being logged in).Verification code spoofing — the endpoint /send_code/ was vulnerable to spoofing. By appending the not login token parameter there, the code received to my email address was intended for the account tied to the provided not login token. For example:I entered the username “username” in TikTok account recovery and received a not login token.I’ve provided this token along with my email address that I wished to link plus a verify token at /send_code/.The code was sent and I’ve quickly received it. I’ve noticed at the bottom of TikTok’s email the following message: “This code was generated for username.” Woah, I’ve received a code which was generated for the account “username”, even though I didn’t have access to such account! This meant that the Not Login Token somehow tricked the emailing system into giving me verification code intended for account I didn’t own.Great! So now what… Well, there was one more obstacle. It’s true that /email/update/ didn’t check correctly for the verify token, but the endpoint responsible for sending the spoofed OTP on the email address I wanted to link, /send_code/, checked correctly for this token. I had one more trick under my sleeve though (lol). When I previously talked about the OTP bypass for phone number unlinking, I mentioned the verify token which is generated in 2FA settings when you enter the correct password of your account. For some reason, this token had too many permissions in TikTok’s backend. It should have been limited to only the account you’re logged into, but this token had critical changing permissions for any account. Therefore, when this verify token was appended to the /send_code/ endpoint, the OTP was successfully sent no matter the requested account in not login token parameter.
Now I had everything I needed to perform the account takeover. Here’s what I did:
I went into the TikTok account recovery center and obtained a not login token for the username “username” (Disclaimer: I did not, it was username of an account which I actually owned.)Then, I logged into my TikTok account which I had access to and which had a linked email.I went to 2FA settings and entered the password of my account to obtain a verify token (so now I had both verify token and not login token).Next, I went to account information, clicked on email, clicked on change email and sent a code. I did not need to know this code, so I entered an arbitrary one (e.g. 111111), intercepted the request, and replaced the invalid OTP response with the verify token response I’ve received in the 2FA settings.Then, I entered the new email address that I wished to have on the account “username”, clicked on send code and intercepted the request again.In the next request, I added the not login token which ensured the OTP I’ll receive to my email address will be for the account “username”. The verify token from the previous response that I’ve modified was already appended.I checked the received OTP, entered it, and a request on the /email/change/ endpoint was generated with the following: email=mynewemail@example.com&verifytoken=ABCDEFG&code=spoofed_code_that_i_receivedNow I just needed to insert the not login token into these params as well. Once done, I forwarded the request. The response was simply “Success”.The email was now changed on the account I did not have access to. Now I simply went to the password reset page and reset the password through the newly linked email address & gained access to the account.
This worked for all accounts, even accounts which did not have a linked email before, as the /email/change/ endpoint (which was supposed to be for email changes only) simply added the email as well (so it had the same functionality as /email/bind/ endpoint which is for adding email address if no email is currently linked).
This issue was reported by me & awarded $12,000 at the beginning of 2024. It was quickly patched and the /email/change/ endpoint validated the verify token, plus the token which I got from 2FA settings was finally getting validated on the /send_code/ endpoint for the specific account and not globally.
Again, try to focus as much as possible, as this might be hard to understand on the first read. When I was looking for third account takeover after 2 account takeovers and multiple other issues found, I knew how the API worked deep down, to the slightest detail. Without this, I would’ve probably never discovered this.
I mentioned above on account takeover number 2 that the endpoint /email/change/ finally validated the verify token for the specific account, so if you wanted to get this token for the account you wanted to “take over”, you needed to actually enter the correct OTP for the account where you wanted to change the email and verify your identity. But as I mentioned before, “The issue is that, for some reason, TikTok decided to implement the same verify token on other endpoints with different verification options.” This led not only to another account takeover, but also 2FA bypass for email OTP verification.
Going back to the account recovery and 2FA settings
When turning on 2FA on your account, the process works like this:
If your device is not trusted:
A request to /verification_manage/ endpoint is made, no verify token is returned as your device is not trusted, password is needed to be entered in order to obtain this verify token.Another request is made to /account/verify/ with the provided password. If it’s correct, a token is issued.This token is then used as some form of authorization to update the 2-factor authentication (2FA) settings.If your device is trusted:
A request to /verification_manage/ endpoint is made, and since your device is trusted, the backend issues the verify token without any need for verificationThis token is then used as some form of authorization to update the 2-factor authentication (2FA) settings.How TikTok determines if your device is “trusted”
TikTok’s backend uses a device identifier parameter (did=ABCDEFG) in order for the API to work correctly. This identifier is assigned to your device once you download TikTok for the first time, and cannot be changed unless you completely reset your device. Every action you do on TikTok is tied to this device identifier. This means that TikTok can store information internally, for example what exact actions did this device identifier do, in which accounts was it logged in, etc. But being previously logged in a specific account is not enough for TikTok’s backend to make your device trusted. Specifically, the endpoint /verification_manage/ issues a verify token if the following condition is met: You’ve entered a correct password of the account or correct email/phone number OTP within the last 30 seconds. So, to get this verify token without any verification, you must request it right after entering the correct password or phone number/email OTP for the same account anywhere in any setting.
To put it more clearly, here’s a quick example: I’ve just logged into my TikTok account. Because I’ve used my password to login, I can quickly go to the 2FA settings and get the verify token without any verification, but I need to make sure it’s within 30 seconds, otherwise it will ask for password.
Another example: I just used a verification code to change my account’s password in account settings. Because I entered the correct code, my device identifier got validated for 30 seconds, and I could request verify token without any verification. Hopefully it’s more clear now.
Same issue again though — the verify token can be used across various TikTok settings, including removing phone number, changing the password, and changing the email.
Yes, TikTok indeed fixed the verify token validation issue at /email/change/, but they forgot about the fact that the not login token (the one you get from account recovery) can be used instead of a valid session ID along with a valid verify token issued for a specific account to change the email of an account without the need of being logged in. The not login token also worked on the /verification_manage/ endpoint which issued the verify tokens.
This meant that I could potentially get both verify token, not login token and then change the email address without being logged in. I had two things: not login token, and the /email/change/ endpoint which didn’t need session ID and accepted the not login token. Only one thing was missing; a verify token. It took me a while to figure out how to get that for a specific account without being logged in, but I eventually did.
How I obtained a valid verify token for a specific account without login
I wasn’t telling you information about how the /verification_manage/ endpoint works for no reason. Same goes for the flawed OTP verification system. This is the exact endpoint which gave out critical and confidential verify token by a misconfiguration. I was able to discover this by putting multiple pieces together. Here’s exactly how I did it:
First, I obtained a not login token in account recoveryThen, I used this token to send OTP to my email address, but I actually received OTP for the target accountI entered the OTP, appended the not login token again on the /check_code/ endpoint, and forwarded the requestThis resulted, by misconfiguration, in my device identifier being validated for the target account for exactly 30 secondsThen, I simply needed to make a request to /verification_manage/ with the same not login token within 30 seconds of verifying the previous OTP, which gave me a valid verify token assigned to the target accountAfter this, I used both not login token and verify token to change the email address at /email/change/. The response was again “Success”. Now I could use the newly linked email address to login to the account.
This also bypassed email 2FA, as having the ability to change the email address without being logged in rendered the email 2FA useless.
What should have TikTok done to prevent this
Implement a simple validation for each issued verify token, which would tie this token to the endpoint it was granted for in the backend.Completely remove not login token for account recovery check, implement a more direct system with a single request instead of 3 request + token. The request will simply contain the account username, and the response will simply contain information about what’s linked.If not login token were to stay, then at least limit the usability of such token for account recovery only, not for sending verification codes and who knows what else. TikTok partially fixed this, but it still could be much better.This vulnerability was patched, but marked as “duplicate”. This vulnerability was quite advanced for anyone to easily find it, and the linked original report was submitted exactly a day before mine (I reported this vulnerability 2 days after discovering it). That’s too much coincidence, and I believe TikTok tracked my device identifier after I’ve provided it in my previous HackerOne reports, then some intern submitted the report before me. TikTok, if you don’t want to pay out your researchers, just say it. That’s about $12,000-$15,000 loss. Since this incident, I’ve actively stopped doing a research on TikTok’s API systems.
The vulnerabilities I discovered, especially around TikTok’s “not login token” and its over-permissiveness, highlight the importance of thoroughly auditing API functionality and endpoints in modern applications. Many of the issues could have been mitigated with more stringent validation practices and by limiting the scope of certain tokens. TikTok has since patched the most critical of these issues, but as with any system, constant vigilance is needed to ensure the security of its users.
I hope this article serves as a reminder of the complexity of cybersecurity in large platforms like TikTok. Even with advanced security measures in place, small oversights can lead to significant vulnerabilities, potentially allowing attackers to bypass 2FA or gain unauthorized access to user accounts.
Finally, I urge researchers and security professionals to follow responsible disclosure practices and always prioritize the protection of users. Ethical hacking is about identifying and fixing vulnerabilities, not exploiting them. By working together with platforms like TikTok, we can help create a safer and more secure digital ecosystem for everyone.
If you found this writeup interesting, make sure to comment your thoughts on it :)
X (Formerly Twitter): @vojtechcekal