From the POC authorization URL, the redirect_uri parameter and value are:
redirect_uri=https%3A%2F%2Foutlook-integration.harvestapp.com%2Fauth%2Foutlook-calendar%2Fcallback?state=%7b%22return_to%22:%22/time%22%2c%22subdomain%22:%22example.com/%22%7d
So if Harvest registered the redirect_uri as: https%3A%2F%2Foutlook-integration.harvestapp.com%2Fauth%2Foutlook-calendar%2Fcallback
then why does any extra URL parameters added to that value get accepted by the Microsoft OAuth server before authorization, when they clearly do not match the registered one?edit: I tried authorizing using another OAuth server provider, with a changed redirect_uri by appending URL parameters to the encoded value, and the OAuth server (I believe, quite rightly) rejected the authorization request.
Go the some harvest authorize url,
That redirects to the Microsoft authorize url with redirect_uri=registered_uri and state=some_encoded_final_uri,
user enters credentials,
redirect to a registered uri
read state parameter and redirect to uri encoded in state.
This exploit still redirect to an authorized uri, then authorized uri then reads the the state parameter and happily forwards the response.
3 mistakes in this, abusing state, not encypting and validing state if you are going to abuse it. Enabling implicit grant(even if they needed it, should have made a second registration with limited uses).
For example, if you're making a shopping website and a user asks to put something in their basket and you send them to log in, you'd want to return them to the item they were about to buy, not dump them back at the homepage.
What's the proper way of doing this, without "abusing state" ?
Ideally you would 'consume' the token before redirecting, and not send it to the second redirecting url.
If for some reason you really do need to transmit this data in-band (ultra rare use case) you should at least be using something like HMAC to verify that all carriers have transported the data unmodified. It is your responsibility to ensure the integrity of the data end-to-end.
But some providers allow query parameters. For Microsoft, it was possible in 2020 when I reported the vulnerability. In 2022, they restricted query parameter support to only applications that is built for Work and School accounts and in August 2022, they added a section for this in the documentation.
See: - Commit: https://github.com/MicrosoftDocs/azure-docs/commit/c249a0548... - Current Documentation: https://learn.microsoft.com/en-us/azure/active-directory/dev...
> The authorization server MUST require public clients and SHOULD require > confidential clients to register their redirection URIs. If a redirection > URI is provided in the request, the authorization server MUST validate it > against the registered value.
So how is this possible, when presumably the Harvest app did not register the malicious redirect_uri?
Does the Microsoft OAuth server ignore URL parameters within a redirect_uri when comparing with registered redirect URIs for the OAuth client?