Introduction
During a recent security assessment, it was identified that a client web application integrating Microsoft Entra through the Microsoft Graph API was vulnerable to a novel form of filter injection. This flaw originated in the password reset functionality, where user-supplied input was incorporated directly into Graph API queries without adequate sanitization or validation. Exploiting this weakness allowed bypassing password reset token validation, ultimately enabling unauthorized password resets for arbitrary user accounts. This article details the discovery process and demonstrates practical payloads used to exploit the issue.
Technical description
The story begins with the typical functionality of a web application – password reset. Commonly, password resets are done with a URL token (https://cheatsheetseries.owasp.org/cheatsheets/Forgot_Password_Cheat_Sheet.html#url-tokens) as it was in this case. During the password change, the application sent a POST request with the following content:

The token looked like a good place to try an injection attack. A modified payload was submitted:

The value ’ or 1=1– is a classic SQL injection test payload. Instead of some generic error, the application returned an unusual and verbose response:

Further investigation revealed that this syntax corresponded to Microsoft Graph API query filters (https://learn.microsoft.com/en-us/graph/use-the-api). No prior references to similar “Microsoft Graph API injection” behavior could be found, suggesting this was a novel case, likely due to the client application’s custom integration with Microsoft Entra.
After analysing the above error and documentation of Graph API it was found out that logical operators can be used in the queries. The following payload gave a promising result:

This resulted in error:

The injected ‘) closed the original function call, and startswith(employeeid,‘a began a new one. The query was now syntactically valid, but ineffective, as the system still required a match with the provided username (test@example.com).
Additional operators were tested to further understand the behavior. For example:

This was rejected, but confirmed usage of Microsoft Graph API (with Microsoft Entra):

The next objective was to craft a payload that evaluated the entire filter expression to true. This was achieved with:

This payload can be broken down into:
- notimportant’) - closed the initial, unseen portion of the query; evaluates to false.
- startswith(userPrincipalName,’test’) - matched the login test@example.com; evaluates to true.
- startswith(employeeid,’notimportant - closed the final part of the query evaluates to false.
- The OR operator is used in between so: “false” or “true” or “false” gives true - the query is evaluated to true.
As a result, it became possible to reset the password for any user account without knowing the valid token, provided the attacker knew the username or email.
However, the attack could be further optimized. One limitation was that usernames and email addresses did not always match, as users could configure them independently. In this case, error messages also helped. When changing email address in the account it was possible to trigger following error:

This indicated otherMails is the property holding the email address information and can be used in queries. A new payload was constructed: With this query it was possible to reset user password just by knowing their email.

The same behaviour also enabled user enumeration. Another endpoint that was used to update email address was found to be also vulnerable. In this case it returned different error responses based on whether a query matched:

This allowed incremental, character-by-character enumeration of email addresses. There was no rate limiting so to confirm this scenario several email addresses were recovered this way. Thus, it was possible to find any user, then gain access to their account. The only downside of this attack was the necessity to send email to the target – victim could get alerted that something happened.
Conclusions
This assessment uncovered a previously undocumented filter injection vulnerability in a custom Microsoft Graph API integration. Verbose error messages made it possible to identify the issue, ultimately leading to full account takeover. By manipulating the queries used in the password reset process, token validation could be bypassed and passwords for arbitrary users could be changed. The same issue also allowed user enumeration, with no rate limiting in place. These findings underline the need for robust input validation, careful query handling, and generic error messaging when working with Microsoft Graph API to prevent similar high-impact vulnerabilities.



