Akwaaba! once again people. My lazy ass finally found time to write about this simple yet impactful vulnerability I came across during my hunting on a HackerOne program last year. If you haven’t read my previous post about Easy $150: Misconfigured SSO Led to Account Takeover, please do — it's a simple exploit you can also do to earn a few $$$.
Alright, I’m not gonna bullshit you or sensationalize this, it was a simple vulnerability that doesn’t require any mental gymnastics.
Yeah, that’s it. As described in the image above, there was a Sensitive Data Exposure vulnerability in the REST API. By simply changing the API endpoint from /api/user/me to /api/user/all, we are able to dump all existing user information.
Some general recon, subdomain discovery revealed a domain:
I was able to sign up via a registration page. After signing up, I logged in with my account. Taking note of the API calls being made when you visit the app loads, I noticed the API wasn’t hosted on a different subdomain, instead, it was hosted on a dedicated /api path. So, we have all API calls being made to
Upon successful login, an API call is made to:
via a GET request and your account details are returned. These details get rendered to browser interface for your view. As you can see, the Content-Length of this response was 440.
So, I tried the classic attack of changing the path from /api/user/me to /api/user/all and it worked! This returned a large response as seen by the Content-Length. I was surprised myself because this was such a CTF-style exploitation which I didn’t expect to come across.
That wasn’t the end of it, I noticed, the token that was part of the verification link sent to my email was also leaked in my account details. It was contained in the verify_identity parameter.
So, I dialed up my French and quickly compared this token to the one in my email and I was right! They matched.
I run back to the /api/user/all endpoint to see if the tokens of other users are leaked there also. Yes, their tokens were leaked! I got access to 3,156 tokens of various types of users.
Like I said, this was quite simple:
Login => Grab /api/user/me Request => Change /me to /all
It is a common endpoint where developers tend to store all user information, I have come across it in many pentests but it was mostly limited to internal applications. So, I decided to give it a shot. Whenever I see a /api/me API endpoint, some similarly misconfigured endpoints I normally check for include:
As a developer, before you pull this shameless line on me:
But the application doesn’t make a request to the /api/user/all endpoint by itself, you had to manually request it by yourself
Just know the vulnerability exists, it is THERE! Implement proper access controls. If you are going to keep this endpoint up, perhaps limit it to administrators or internal use only. For example, in Flask, you can check the user’s role from their JWT payload before granting/denying access.
@app.route('/api/user/all', methods=['GET'])
@jwt_required()
def get_all_users():
# get_jwt_identity() method returns the user's role from their JWT
current_role = get_jwt_identity()
if current_role == 'admin': # Only allow admin to access this endpoint
return jsonify(users), 200
return jsonify({"msg": "Access forbidden"}), 403if __name__ == '__main__':
app.run(debug=True)
Hey, see you later.