October 25, 2026
The User Was Removed. The Access Wasn’t.
An unexpected API documentation discovery led me to a Broken Access Control vulnerability.

By Ashour0x
3 min read
When testing a web application, I usually start with the browser, Burp Suite, and the requests generated by the frontend.
But this time, I found something different.
I was exploring the application's API documentation when I came across an endpoint I didn't recognize:
GET /api/page/{pageId}/info
I didn't know exactly how it was used, so I tried to find it in my Burp history.
Nothing.
I searched through the requests I had captured while interacting with the application. I tried to find a frontend action that triggered it, but I couldn't find one.
The endpoint was documented, but I couldn't connect it to anything I had seen in the application.
Naturally, I wanted to understand what it did.
A Valid JWT and One Missing Piece
I decided to test the endpoint directly using a valid JWT from a test account I controlled.
The request looked simple:
GET /api/page/<PAGE_ID>/info HTTP/2
Host: <TARGET_HOST>
Authorization: Bearer <VALID_JWT>GET /api/page/<PAGE_ID>/info HTTP/2
Host: <TARGET_HOST>
Authorization: Bearer <VALID_JWT>But the endpoint needed one more thing: a pageId.
That raised the next question: How could I obtain a Page ID legitimately, and what would happen if I kept it after losing access?
I explored the application and its project structure. A Page ID was available through the Page's legitimate URL and requests when the user had access.
Now I had what I needed to test the endpoint.
The Response Revealed More Than I Expected
Using a Page ID from a private Page I was authorized to access, I sent the request.
The response contained much more than a Page name. It included private Page metadata and a list of members, with fields such as:
- User IDs
- Email addresses and names
- Profile-picture URLs
- Permission levels
- Page information, including whether it was public
A simplified, redacted example looked like this:
{
"_id": "<REDACTED_PAGE_ID>",
"name": "Private Project Page",
"isPublic": false,
"createdBy": {
"permissions": 500,
"user": {
"email": "<REDACTED_EMAIL>",
"name": "<REDACTED_NAME>",
"picture": "<REDACTED_PROFILE_PICTURE_URL>"
}
},
"users": [
{
"permissions": 500,
"user": {
"email": "<REDACTED_ADMIN_EMAIL>",
"name": "<REDACTED_ADMIN_NAME>",
"picture": "<REDACTED_IMAGE_URL>"
}
},
{
"permissions": 100,
"user": {
"email": "<REDACTED_MEMBER_EMAIL>",
"name": "<REDACTED_MEMBER_NAME>",
"picture": "<REDACTED_IMAGE_URL>"
}
}
],
"notebook": "<REDACTED_NOTEBOOK_ID>",
"userPermissions": {
"permissions": 500
}
}{
"_id": "<REDACTED_PAGE_ID>",
"name": "Private Project Page",
"isPublic": false,
"createdBy": {
"permissions": 500,
"user": {
"email": "<REDACTED_EMAIL>",
"name": "<REDACTED_NAME>",
"picture": "<REDACTED_PROFILE_PICTURE_URL>"
}
},
"users": [
{
"permissions": 500,
"user": {
"email": "<REDACTED_ADMIN_EMAIL>",
"name": "<REDACTED_ADMIN_NAME>",
"picture": "<REDACTED_IMAGE_URL>"
}
},
{
"permissions": 100,
"user": {
"email": "<REDACTED_MEMBER_EMAIL>",
"name": "<REDACTED_MEMBER_NAME>",
"picture": "<REDACTED_IMAGE_URL>"
}
}
],
"notebook": "<REDACTED_NOTEBOOK_ID>",
"userPermissions": {
"permissions": 500
}
}The response exposed information about multiple members, not just the Page owner.
However, I still needed to answer the most important question: would this endpoint respect access revocation?
The Real Test: What If I Was No Longer a Member?
I used test accounts under my control to test the access-control behavior.
First, I obtained the Page ID while the test user had legitimate access. Then, the administrator removed that user from the Page.
I repeated the same API request with the same valid JWT and the previously obtained Page ID.
The endpoint still returned 200 OK and disclosed the Page information.
I then tested removing the user from the parent Notebook as well. The endpoint continued returning the private Page information.
That changed the significance of the finding.
This wasn't just a question of whether a user could see information while they were a member. The endpoint continued providing that information after the user's access had been revoked.
It Could Reveal Changes Made Later
I also tested whether the response was limited to information the removed user had already seen.
Using the administrator account, I changed the Page's membership and permissions. I then requested the endpoint again.
The response reflected the updated information.
That meant a former member could repeatedly query the endpoint to observe changes to the Page's members and their permission levels, even after being removed.
Depending on the information returned, this could expose member identities, contact information, profile pictures, and access levels to someone who was no longer authorized to view the Page.
Why the Endpoint Was Vulnerable
The issue came down to the difference between authentication and authorization.
The endpoint accepted a valid JWT, but it did not adequately enforce whether the authenticated user was still authorized to access the specific Page ID in the request.
A valid token tells the application who is making the request. It does not automatically grant access to every resource.
The expected behavior was straightforward: once a user lost access to a private Page, the API should no longer return that Page's private information to them.
Instead, the endpoint continued responding successfully.