# API: missing invalidation of OAuth2 Authorization Code during access revocation causes authorization bypass

Vimeo OAuth2 did not invalidate authorization codes on app revocation, letting a malicious app exchange a stale code for a fresh access token after the user disconnected it.

- Payout: hidden
- Severity: medium
- Program: Vimeo
- Found by: dor1s
- Disclosed: 2015-05-31
- Write-up quality: 7/10
- Original: https://hackerone.com/reports/57603
- Library page: https://bugbountylibrary.com/r/h1%3A57603
- Tags: area:web domain:api impact:ato impact:integrity kind:bounty platform:hackerone sev:medium tech:oauth vuln:access-control vuln:auth-bypass

**Target:** OAuth2 authorization endpoint / token exchange API
**Root cause:** On access revocation Vimeo revoked issued access_tokens but not previously issued OAuth2 authorization codes, so an unused code remained exchangeable for a new token.
**Steps:**
1. Request authorization: `https://api.vimeo.com/oauth/authorize?response_type=code&client_id=79658bbee0da8be5254a5137bc0fcc93f7059a2a&redirect_uri=https://avuln.com/callback&scope=public&state=0123456789abcdef`
2. Log in and click Allow; capture `code` from callback URL
3. Exchange code for access_token via getAccessToken.sh; confirm token works against /me
4. Repeat authorization flow and click Allow again; save the new `code` (e.g. `82e24f835184f47cd83f249907e7bd5018bf62c9`) without exchanging it
5. Go to https://vimeo.com/settings/apps and Disconnect the application
6. Confirm old access_token now returns 401 invalid_token
7. Exchange the saved stale code: `./getAccessToken.sh 82e24f835184f47cd83f249907e7bd5018bf62c9`
8. Use the new access_token against /me; it returns 200 with user data
**How found:** Reasoned about the OAuth2 flow's intermediate artifacts: since revocation invalidates access_tokens, the authorization code (also a credential) should be invalidated too; tested by saving a code, revoking, then exchanging it.
**Exploitation:** A malicious app obtains a fresh authorization code while the user is authorizing, holds it unexchanged, and waits for the victim to revoke access. After revocation the app exchanges the stale code for a new access_token, regaining full access despite the user's disconnect.
**Insight:** When auditing OAuth revocation, enumerate every credential artifact in the flow (codes, refresh tokens, device codes, sessions) and test each for post-revocation validity, not just the access token.

