Insufficient OAuth Revocation

HackerOne report #892427 by benaubin on 2020-06-05, assigned to @jbroullon:

Summary

When a user revokes OAuth access to an app, access grants are not revoked. Generally, access grants have a 10 minute lifespan and are revoked upon use (with proper locking - I've verified - to prevent race-conditions implemented by Doorkeeper). This would theoretically make attacks difficult, however, an application may silently send a user through the authorization flow any time after first authorization, making this significantly more plausible.

For example, imagine a user browsing a third party site, then noticing something fishy (maybe a privacy policy). The user decides to revoke GitLab access to that app, but before closing the tab - or maybe when visiting another page on the site, is sent through the OAuth authorization flow. The 3rd-party site can store the grant and redeem it any time in the next 10 minutes.

If that user revokes the 3rd-party app's access less than 10 minutes after going through an authorization flow, the third-party app can silently reauthorize.

Steps to reproduce

Perform an authorization code flow, as usual.

  1. Start an authorization flow (send the user to /oauth/authorize).
  2. Redeem code for access token (POST /oauth/token).
  3. Send the user back to /oauth/authorize. As they have already authorized the user, they likely won't notice this redirect.
  4. This time, don't redeem the code for an access token, store it for later use.
  5. Send the user to their expected destination.
  6. As the user, use /oauth/applications on GitLab.com to revoke the application's access.
  7. Within 10 minutes of step 3, redeem the stored authorization code for a new access token

Cause & Fix

When a user revokes access to an OAuth application, only access tokens are revoked.

Current implementation (app/controllers/oauth/authorized_applications_controller.rb#L19).

 Doorkeeper::AccessToken.revoke_all_for(params[:id], current_resource_owner)  

Add a line to revoke access grants:

 Doorkeeper::AccessGrant.revoke_all_for(params[:id], current_resource_owner)  

Other recommendation

Send "third-party app connected" emails when an OAuth app is connected, to help mitigate the risk of an app silently gaining access to a user's account. This gives users the ability to spot fishy things occurring after-the-fact.

Impact

A third-party app can silently regain OAuth access to user's account after revocation, if that user visited the third-party's site at all, including through an invisible redirect, in the 10 minutes prior to revocation.