July 18, 2026
Authorization Bypass via Privilege Persistence After Role Downgrade in Hasura PromptQL
Still an Admin. Just Not Officially
By Ahmed Embaby
4 min read
بِسْمِ اللَّهِ الرَّحْمَٰنِ الرَّحِيمِ،
وَالصَّلَاةُ وَالسَّلَامُ عَلَى النَّبِيِّ الْمُجَاهِدِ الشَّهِيدِ،
اللَّهُمَّ انصُرْ أَهْلَ غَزَّةَ وَفِلَسْطِينَ وَالسُّودَانَ، وَطَهِّرِ الْأَقْصَى مِنْ دَنَسِ الْيَهُودِ،
أَمَّا بَعْدُبِسْمِ اللَّهِ الرَّحْمَٰنِ الرَّحِيمِ،
وَالصَّلَاةُ وَالسَّلَامُ عَلَى النَّبِيِّ الْمُجَاهِدِ الشَّهِيدِ،
اللَّهُمَّ انصُرْ أَهْلَ غَزَّةَ وَفِلَسْطِينَ وَالسُّودَانَ، وَطَهِّرِ الْأَقْصَى مِنْ دَنَسِ الْيَهُودِ،
أَمَّا بَعْدُHi, I'm Ahmed Embaby, a cybersecurity researcher specializing in Web Application Security, Vulnerability Research, and Offensive Security. My work focuses on identifying authorization flaws, business logic vulnerabilities, GraphQL security issues, and other high-impact security weaknesses through responsible disclosure.
Introduction
While assessing the security of Hasura PromptQL, I identified an authorization flaw that allowed a user to continue performing administrative actions even after their administrator role had been revoked.
The issue occurred when an Administrator was downgraded to a Member while still holding a previously issued authenticated session. Although the role change was immediately reflected in the user interface, the existing authenticated session continued to authorize privileged GraphQL mutations.
As a result, a downgraded administrator was able to remove project members despite no longer having the required permissions, effectively bypassing the intended authorization model during role transitions.
Discovery
While reviewing the project member management functionality, I became interested in how the application handled authorization after a user's role changed.
Instead of testing whether a low-privileged user could gain administrative capabilities, I wanted to verify whether an existing administrator would immediately lose those capabilities after being downgraded to a regular member.
To verify this behavior, I created a test project containing three users:
The Owner was responsible for managing user roles, while the Administrator had permission to remove project members.
While logged in as the Administrator, I initiated the member removal action and intercepted the corresponding GraphQL mutation using Burp Suite. Instead of sending the request to the server immediately, I kept it pending.
Before forwarding the intercepted request, I switched to the Owner account and downgraded the Administrator to a regular Member.
The administrative functionality immediately disappeared from the user interface, confirming that the role change had already taken effect.
I then returned to Burp Suite and reissued the previously captured request using the same authenticated session without modifying it.
Unexpectedly, the server accepted the request, and the target member was successfully removed.
This confirmed that the backend continued authorizing privileged operations even though the request originated from a user whose administrative privileges had already been revoked.
Why Did This Happen?
At first, the behavior appeared to be a normal consequence of using stateless authentication tokens.
Access tokens are commonly designed to remain valid until they expire, allowing applications to avoid querying the database for every request. However, authentication alone should not determine authorization for sensitive operations whose permissions may change during an active session.
The vulnerability was not the existence of a valid session token itself.
Instead, the issue was that authorization decisions for privileged GraphQL mutations continued trusting outdated privilege information after the user's role had already changed.
Based on the observed behavior, the authorization layer appeared to rely on privilege information associated with the existing authenticated session instead of validating the user's current role when processing each request.
This created a temporary privilege persistence window, allowing a downgraded administrator to continue performing administrative actions until the existing authorization context was no longer accepted.
After responsible disclosure, Hasura confirmed the behavior and redesigned their authentication model. According to their response, authentication was migrated to a webhook-based mechanism that validates a user's current state including account status and administrative privileges against the database on every request, rather than relying solely on previously issued JWTs. As a result, role changes now take effect immediately, preventing previously issued tokens from continuing to authorize administrative operations after a role downgrade.
Proof of Concept
The vulnerability can be reproduced using the following steps.
Step 1 Prepare the Test Environment
Create a test project containing three users with the following roles:
- User A — Owner
- User B — Administrator
- User C — Member
The Owner is responsible for managing user roles, while the Administrator has permission to remove project members.
Step 2 Capture an Administrative Request
Log in as User B (Administrator).
Navigate to:
Project Settings > Members
Attempt to remove User C while intercepting the request using Burp Suite.
The intercepted GraphQL mutation responsible for removing a project member was:
mutation RemoveProjectMember($promptql_user_id: uuid!) {
remove_project_member(promptql_user_id: $promptql_user_id) {
status
}
}mutation RemoveProjectMember($promptql_user_id: uuid!) {
remove_project_member(promptql_user_id: $promptql_user_id) {
status
}
}Keep the request pending without forwarding it.
Step 3 Downgrade the Administrator
Log in as User A (Owner).
Change User B is role from:
Administrator
to
Member
Verify that the user no longer has access to administrative functionality through the user interface.
Step 4 Reissue the Captured Request
Return to Burp Suite.
Reissue the previously captured request using the same authenticated session.
The server accepted the request and returned:
{
"data": {
"remove_project_member": {
"status": "removed"
}
}
}{
"data": {
"remove_project_member": {
"status": "removed"
}
}
}Although the requester was no longer an administrator, the member was successfully removed.
A video demonstrating the complete reproduction steps is available here:
https://drive.google.com/file/d/16_DtNy9zodCc2nY8u4oA0VBVhnK3CM9B/view?usp=sharing
Impact
This vulnerability allowed administrative privileges to persist after a user's role had been downgraded.
As a result, a user who no longer held administrative permissions could continue performing privileged GraphQL mutations using an existing authenticated session.
This effectively broke the Principle of Least Privilege (PoLP) and created a temporary inconsistency between the user's actual role and the authorization enforced by the backend.
Although this research verified the behavior using the remove_project_member GraphQL mutation, the same authorization model could potentially affect other privileged GraphQL mutations that rely on the same authorization mechanism.
Vendor Response and Fix
The issue was responsibly disclosed to the Hasura Security Team.
After investigating the report, the team confirmed the behavior and confirmed the behavior and informed me that they were implementing mitigations while assessing the overall impact. to address the authorization inconsistency.
Once the fix was deployed, Hasura explained that authentication had been migrated to a webhook-based model that validates a user's current state — including account status and administrative privileges — against the database on every request, rather than relying solely on previously issued JWTs. This architectural change ensures that role and privilege changes take effect immediately, preventing previously issued tokens from continuing to authorize administrative operations after a user's privileges have been revoked.
After receiving the update, I repeated the original proof of concept and confirmed that the authorization bypass was no longer reproducible.
Conclusion
This case highlights how authorization flaws can emerge even when authentication is functioning as intended.
While stateless authentication mechanisms such as JWTs provide scalability and performance benefits, authorization decisions for privilege sensitive operations should always reflect the user's current state rather than previously issued credentials.
Revalidating permissions after role changes eliminates privilege persistence windows, ensuring that administrative actions remain consistent with a user's actual privileges.
The issue was responsibly disclosed to Hasura, who confirmed the behavior and redesigned their authentication and authorization flow to address the underlying authorization inconsistency. After validating the deployed fix, I confirmed that the issue was no longer reproducible. In recognition of the report and the architectural improvements it prompted, Hasura awarded a $250 bounty.