<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Blog | Mirzadzare (Spix0r)]]></title><description><![CDATA[Just sharing my bug hunting journey with daily reading, notes, and useful tips. Follow for real experiences, new findings, and useful tricks in bug bounty hunti]]></description><link>https://blog.mirzadzare.net</link><generator>RSS for Node</generator><lastBuildDate>Sat, 11 Apr 2026 05:44:54 GMT</lastBuildDate><atom:link href="https://blog.mirzadzare.net/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[IP Spoofing to Account Takeover: You Patched It? Really?]]></title><description><![CDATA[Abstract
In my previous article, I described how I found a security flaw in a popular desktop app's OAuth flow that allowed me to steal any user's account with just one click. I reported it, saw it pa]]></description><link>https://blog.mirzadzare.net/ip-spoofing-to-account-takeover</link><guid isPermaLink="true">https://blog.mirzadzare.net/ip-spoofing-to-account-takeover</guid><category><![CDATA[bugbounty]]></category><category><![CDATA[cybersecurity]]></category><category><![CDATA[#cybersecurity]]></category><category><![CDATA[bugbountytips]]></category><category><![CDATA[hacking]]></category><category><![CDATA[oauth]]></category><category><![CDATA[authentication]]></category><dc:creator><![CDATA[Mohammad Reza Mirzadzare]]></dc:creator><pubDate>Fri, 20 Feb 2026 11:30:46 GMT</pubDate><enclosure url="https://cloudmate-test.s3.us-east-1.amazonaws.com/uploads/covers/69207a5a005b143f71163caa/6c0c14e1-e484-47db-8cca-e620e6dd5119.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2><strong>Abstract</strong></h2>
<p>In my <a href="https://blog.mirzadzare.net/from-log-in-with-oauth-to-your-account-is-mine-desktop-app-edition">previous article</a>, I described how I found a <strong>security flaw</strong> in a popular desktop app's OAuth flow that allowed me to <strong>steal</strong> any user's account with just <strong>one click</strong>. I reported it, saw it <strong>patched</strong>, and then <strong>bypassed</strong> the patch <strong>again</strong>. Since the process of bypassing and exploiting the flaw is interesting to me, I decided to write a second article about it. I also tried to get permission to disclose the report, but they didn't allow me to do so. Therefore, throughout this post, I'll refer to the domain as <a href="http://redacted.com">redacted.com</a>.</p>
<h2>Setup</h2>
<p>Since the setup environment <strong>hasn't changed,</strong> I refer to the setup section of <a href="https://blog.mirzadzare.net/from-log-in-with-oauth-to-your-account-is-mine-desktop-app-edition#heading-setup">this</a> write-up.</p>
<h2>Reconnaissance</h2>
<p>After the vulnerability was <strong>patched</strong>, I tried to do the same thing I did before to see what would <strong>prevent</strong> me from taking over a victim's account.</p>
<h3><strong>Analyzing The Patch</strong></h3>
<p>I followed the <strong>previous attack scenario</strong> explained <a href="https://blog.mirzadzare.net/from-log-in-with-oauth-to-your-account-is-mine-desktop-app-edition#heading-attack-scenario">here</a>, and you can see its diagram in the image below.</p>
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1771452258913/ef9e470a-9b19-4b9e-8ee6-22ece75fb08a.png" alt="" style="display:block;margin:0 auto" />

<p>As an attacker, I <strong>initiated</strong> the OAuth login process in my <strong>desktop app</strong>. I copied the generated OAuth URL (<code>https://oauth2.redacted.com/auth/google?remote_key=[ATTACKER_REMOTE_KEY]&amp;jwt=1&amp;client_id=[CLIENT_ID]&amp;lang=en&amp;return_skip=1</code>) from the <strong>browser</strong> it opened and then opened it on the <strong>victim’s device</strong> with a <strong>different IP</strong>. However, after completing the OAuth process on the victim’s device, I <em>wasn't</em> able to log in to the attacker’s desktop app as the victim, as I expected.</p>
<p>The patched version showed me the following page:</p>
<img src="https://cloudmate-test.s3.us-east-1.amazonaws.com/uploads/covers/69207a5a005b143f71163caa/8429489e-ab8c-4bd3-a422-39a2d8c0eef4.jpg" alt="" style="display:block;margin:0 auto" />

<p>I tried again using a <strong>different device</strong> but the <strong>same IP</strong> through a <strong>VPN</strong>. I discovered that as an attacker, I could take over the victim's account only if our <strong>IPs matched</strong>. This showed that the prevention <strong>relied</strong> only on <strong>IP</strong>, which is usually <strong>not enough</strong>.</p>
<h3>IP Spoofing via HTTP Headers</h3>
<p>By checking all the requests initiated by the <strong>desktop application</strong>, I noticed that all domains are behind the <strong>CDN</strong>, and when a developer puts a domain <strong>behind a CDN</strong>, finding the <strong>real</strong> <strong>client IP</strong> can be <strong>challenging</strong>. This is because there is no <strong>universal</strong>, standardized way for CDNs to convey the <strong>original visitor's IP</strong> to the backend, and this process can vary based on the CDN provider, programming language, server configuration, and other factors.</p>
<p>To obtain the real client IP behind a proxy (such as a CDN) and pass it to the server, several HTTP headers are commonly used:</p>
<ul>
<li><p><code>X-Forwarded-For</code> is a list of comma-separated IPs that gets appended to by each traversed proxy. The idea is that the <strong>first IP</strong> (added by the first proxy) is the <strong>true client IP</strong>. Each subsequent IP is another proxy along the path. The last proxy’s IP is <em><strong>not</strong></em> present (because proxies don’t add their own IPs, and because it connects directly to the server so its IP will be directly available anyway).</p>
</li>
<li><p><code>Forwarded</code> is the most official but seemingly least-used header.</p>
</li>
<li><p>There are also special single-IP headers like <code>X-Real-IP</code> (Nginx), <code>CF-Connecting-IP</code> (Cloudflare), or <code>True-Client-IP</code> (Cloudflare and Akamai).</p>
</li>
</ul>
<p>I prepared a victim's device, saved its <strong>IP</strong>, and initiated the OAuth flow with the attacker's device. This time, I used the <code>X-Forwarded-For header</code> in <strong>every</strong> request made by the Desktop application. Then I opened the generated OAuth URL using the victim’s device, and I successfully logged in as the victim on the attacker's Desktop application.</p>
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1771498172937/07e38cb2-a377-4c68-b503-ab5fe8e4875a.png" alt="" style="display:block;margin:0 auto" />

<blockquote>
<p>As we saw, the patch is <strong>vulnerable</strong>, but one piece of the puzzle is missing for the exploit: How does the attacker find out the victim's IP to initiate the OAuth flow with it?</p>
</blockquote>
<h3>Finding Victim’s IP</h3>
<p>I previously identified a <strong>stored XSS</strong> vulnerability in the <code>redirect_uri</code> parameter of a specific endpoint, which has since been patched. In brief, when users accessed the <strong>Manage Account</strong> section within the <strong>desktop application</strong>, the backend generated a <strong>token</strong> and then triggered a <strong>browser</strong> window opening with a URL structured as <code>https://redacted.com/token?t=Code</code>. This URL facilitated <strong>authentication transfer</strong> from the <strong>application</strong> to the <strong>browser</strong> by leveraging data linked to the <code>Code</code> passed in the <code>t</code> parameter. The Code contained both account information and a <code>redirect_uri</code> value, which dictated the <strong>destination URL</strong> after the authentication process completed. The vulnerability happened because there were <em><strong>no</strong></em> <strong>checks</strong> on the <code>redirect_uri</code>, allowing <strong>harmful</strong> scripts to be added. This issue was <strong>fixed</strong> after my report.</p>
<p>The following request to the backend API shows the request body for generating the <code>Code</code> passed in the <code>t</code> parameter in the URL:</p>
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1771437255402/74578afa-a01b-49cd-aae7-cd04087e7208.png" alt="" style="display:block;margin:0 auto" />

<p>And the <code>Code</code> that you'll receive in response:</p>
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1771439229452/550f56cd-c69a-4783-96a2-05a8026844b8.png" alt="" style="display:block;margin:0 auto" />

<p>I attempted to exploit this feature to <strong>achieve</strong> an <strong>open redirect</strong> by <strong>altering</strong> the <code>redirect_uri</code> parameter to something like <code>mirzadzare.net</code>. I obtained the generated code from the response and opened the URL (<code>https://redacted.com/token?t=code</code>) in a browser. As a result, it <strong>redirected</strong> me to <code>mirzadzare.net</code> after the <strong>authentication transfer</strong>. With this low-impact open redirect, I could <strong>redirect</strong> the <strong>victim</strong> to <strong>my website</strong> and <strong>log their IP!</strong> The puzzle is finally complete.</p>
<h2>Attack Scenario</h2>
<blockquote>
<p>Based on the analyzed flow, the process of logging the victim's IP and initiating the OAuth flow needed to be automated. I decided to write a PHP exploit to mimic the desktop application, capture the victim's access token, and send it to the attacker via a Telegram bot.</p>
</blockquote>
<p>The attack scenario is illustrated in the diagram below:</p>
<img src="https://cloudmate-test.s3.us-east-1.amazonaws.com/uploads/covers/69207a5a005b143f71163caa/f0676bf5-39ab-45ed-a508-9257318add50.png" alt="" style="display:block;margin:0 auto" />

<ol>
<li><p>The attacker <strong>alters</strong> the <code>redirect_uri</code> and sends it to the API endpoint, receiving an <strong>authorization</strong> <strong>code</strong> in response.</p>
</li>
<li><p>The attacker <strong>crafts</strong> a <strong>malicious link</strong> containing this <strong>code</strong> and sends it to the victim.</p>
</li>
<li><p>The victim opens the malicious link.</p>
</li>
<li><p>The exploit sends a request to the desktop application's API to <strong>initiate</strong> the OAuth flow and <strong>simultaneously</strong> establishes a <strong>WebSocket</strong> connection with the backend server.</p>
</li>
<li><p>The exploit opens a login window in the victim's browser (I could do this <strong>without</strong> popping up a window, but for <strong>simplicity</strong> and <strong>clarity</strong>, I did it for the proof of concept.).</p>
</li>
<li><p>The victim enters their <strong>credentials</strong> in the OAuth provider login window.</p>
</li>
<li><p>The exploit <strong>continuously</strong> monitors the <strong>WebSocket connection</strong> and detects when the victim <strong>successfully</strong> logs in and the <strong>access token</strong> is received.</p>
</li>
<li><p>Finally, the exploit sends the <strong>stolen access token</strong> to the <strong>attacker’s Telegram bot</strong>, enabling the attacker to <strong>take over</strong> the victim's account.</p>
</li>
</ol>
<img src="https://cloudmate-test.s3.us-east-1.amazonaws.com/uploads/covers/69207a5a005b143f71163caa/85a696de-b478-4c21-813b-0ec405995dbc.jpg" alt="" style="display:block;margin:0 auto" />

<p>In the POC above, the current browser tab displays the exploit page, while the other shows the company's OAuth login result page. Once completed, the <strong>access token</strong> is sent from the <strong>victim's browser</strong> to the <strong>attacker</strong> via a <strong>Telegram bot</strong>.</p>
<h2><strong>Conclusion</strong></h2>
<p>This writeup shows how <strong>partial fixes</strong> can create a false sense of security instead of removing the risk completely. Even though the original issue was fixed, the patch used <strong>IP-based</strong> <strong>validation</strong> as its <strong>main</strong> trust method, which is weak in modern web setups with proxies, CDNs, and client-controlled headers. By <strong>combining small issues</strong> like IP spoofing and an open redirect, a full account takeover was possible despite the initial fix.  </p>
<p>This case teaches important lessons for developers and security teams. First, don't <strong>rely</strong> only on <strong>changeable client properties</strong> like IP addresses for authentication and authorization. Second, test fixes against real attacker models, not just the original example. Third, small issues like open redirects or header misconfigurations can become <strong>serious</strong> when <strong>combined</strong>.</p>
<blockquote>
<p>Security is about how small weaknesses interact, not just one flaw.</p>
</blockquote>
]]></content:encoded></item><item><title><![CDATA[From "Log in with OAuth" to "Your Account Is Mine" – Desktop App Edition]]></title><description><![CDATA[Abstract

Just one click on a malicious link → account takeover. No phishing, no malware.

I discovered a security flaw in a popular desktop app’s OAuth flow that let me steal any user’s account just ]]></description><link>https://blog.mirzadzare.net/from-log-in-with-oauth-to-your-account-is-mine-desktop-app-edition</link><guid isPermaLink="true">https://blog.mirzadzare.net/from-log-in-with-oauth-to-your-account-is-mine-desktop-app-edition</guid><category><![CDATA[bugbounty]]></category><category><![CDATA[bugbountytips]]></category><category><![CDATA[cybersecurity]]></category><category><![CDATA[#cybersecurity]]></category><category><![CDATA[penetration testing]]></category><category><![CDATA[hacking]]></category><category><![CDATA[oauth]]></category><dc:creator><![CDATA[Mohammad Reza Mirzadzare]]></dc:creator><pubDate>Mon, 01 Dec 2025 08:02:43 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1764576051910/3a8c5ccf-2200-4137-b272-92846e051439.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2><strong>Abstract</strong></h2>
<blockquote>
<p><em><strong>Just one click on a malicious link → account takeover. No phishing, no malware.</strong></em></p>
</blockquote>
<p>I discovered a security flaw in a popular desktop app’s OAuth flow that let me steal any user’s account just by one click. The root causes: missing state validation, long-lived tokens stored after loopback redirect, and blind trust in a <code>remote_key</code> parameter. In this post, I walk you through the exact attack step-by-step, why it worked so cleanly, and how vendors can actually fix it.</p>
<p>A few months ago, I decided to start looking for vulnerabilities in <strong>desktop applications</strong>. To clarify, when I say “<em>finding bugs in desktop apps,</em>“ I mean the parts where a desktop application <strong>interacts</strong> with its <strong>web backend</strong>, like authentication, data exchange, or any other integration points. The target for this write-up is a well-known company. I can't disclose its name, so throughout this post, I'll refer to the domain as <code>redacted.com</code>.</p>
<h2>Setup</h2>
<p>Because I wanted to capture a desktop application's traffic, <a href="https://parsiya.net/blog/2016-02-21-installing-burp-certificate-authority-in-windows-certificate-store/">I installed the BurpSuite certificate on my OS as a root authority.</a> Then, I set up a <strong>system-wide</strong> proxy through BurpSuite and opened the desktop application. When I launched the application and checked the captured requests, I realized that it did not use certificate pinning. This simplified the traffic interception and meant I didn't need <a href="https://frida.re/">Frida</a>.</p>
<h2><strong>Reconnaissance</strong></h2>
<blockquote>
<p><em><strong>Understand the application better than its developers do.</strong></em></p>
</blockquote>
<p>I started using the application like a regular user by clicking on every button and trying out all the features, especially the hidden or small ones <strong>tucked away in corners</strong>, while intercepting the traffic with Burp.The application required you to log in before use, offering two methods: traditional credentials or OAuth.</p>
<p>OAuth flows are particularly interesting to security researchers because there are many ways they can be implemented. The most interesting part is where developers <strong>customize</strong> the flow to suit their needs, as this is where bugs often appear. (The image below is a sample OAuth page from my <a href="https://github.com/Spix0r/safe-blog"><strong>!Safe-Blog</strong></a> <a href="https://github.com/Spix0r/safe-blog"><strong>Project</strong>)</a></p>
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1764417407769/a63c8b99-6e42-4a71-878d-bcc7e3f802a3.png" alt="" style="display:block;margin:0 auto" />

<h3><strong>OAuth Authorization Flow</strong></h3>
<p>I started logging into my account using OAuth. When you clicked on one of the OAuth options, such as “Login with Google” or “Login with Facebook,” a browser window opened with the following URL:</p>
<pre><code class="language-plaintext">https://oauth2.redacted.com/auth/google?remote_key=[REMOTE_KEY]
&amp;jwt=1&amp;client_id=[CLIENT_ID]&amp;lang=en&amp;return_skip=1
</code></pre>
<p>The <code>remote_key</code> was randomly generated each time a user wanted to use OAuth, while the client ID remained the same. This URL then took you to the OAuth provider to log into your account. After you finished the OAuth process, you were redirected to the company website with a message that said, “<em><strong>Login completed, just close the browser.</strong></em>“ When you returned to the desktop app, you saw that you were logged into your account.</p>
<blockquote>
<p><em>The first question I asked myself was:</em> “<em><strong>How was the authentication transferred from the browser to the desktop application?</strong></em>“ I looked for deep links but didn't find any, so I checked the WebSocket section in Burp. I noticed that the desktop app initiates a WebSocket connection with the server right after generating the <code>remote_key</code>. It continuously checks in a loop to see if the user is authenticated. If the user logs in through the browser, the WebSocket server sends back an access token, confirming the user is authenticated, and then the desktop app logs the user into their account.</p>
</blockquote>
<p>Here's what happened in the open WebSocket connection after the authentication was successfully completed:</p>
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1764492878379/10060880-b726-4709-9740-4e4288310303.jpeg" alt="" style="display:block;margin:0 auto" />

<p>So based on these observations, the diagram below illustrates the OAuth flow:</p>
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1764370388323/915bc36d-33ad-4330-9820-7430c74a8001.png" alt="" style="display:block;margin:0 auto" />

<ol>
<li><p>The user opens the <strong>Desktop Application</strong>.</p>
</li>
<li><p>The desktop app displays a <strong>login page</strong> with two options: Login with credentials and Login with OAuth.</p>
</li>
<li><p>The user selects <strong>OAuth Login</strong>.</p>
</li>
<li><p>The desktop app launches the default browser and opens: <code>https://oauth2.redacted.com/auth/google?remote_key=[REMOTE_KEY]&amp;jwt=1&amp;client_id=[CLIENT_ID]&amp;lang=en&amp;return_skip=1</code></p>
</li>
<li><p>The browser shows the OAuth provider page. The user completes the OAuth login.</p>
</li>
<li><p>After successful OAuth authentication, the browser redirects to the company website with a message: “<em><strong>Login completed, just close the browser.</strong></em>“</p>
</li>
<li><p>Meanwhile, right after starting the browser login, the <strong>Desktop App</strong> initiates a <strong>WebSocket connection</strong> to the backend server.</p>
</li>
<li><p>The Desktop App continuously checks the <strong>authentication status</strong> by sending the <code>remote_key</code> to the WebSocket Server in a loop, showing multiple cycles:</p>
<ul>
<li><p>Check #1 → server responds “<em>not authenticated</em>”</p>
</li>
<li><p>Check #2 → “<em>not authenticated</em>”</p>
</li>
<li><p>Check #3 → “<em>not authenticated</em>”</p>
</li>
</ul>
</li>
<li><p>Once the browser OAuth is completed, the server detects the session and sends a <strong>WebSocket response containing an access token</strong>.</p>
<ul>
<li>Check #x → “<em>User Authenticated! (Access_Token: xxxxxxxx)</em>”</li>
</ul>
</li>
<li><p>The desktop app receives the <strong>access token</strong>, marks the user as authenticated, and logs them into their account.</p>
</li>
<li><p>Finally, the <strong>user is logged into the desktop app through the OAuth flow that started from the web browser.</strong></p>
</li>
</ol>
<h2>Attack Scenario</h2>
<p>As a security researcher, the first thing that comes to mind is to test if the <code>remote_key</code> is linked to the desktop application session or an identifier.</p>
<blockquote>
<p>I asked myself: “<strong><em>What happens if I initiate the Login with OAuth</em> <em>process in my desktop app, copy the generated OAuth URL</em> (</strong><code>https://oauth2.redacted.com/auth/google?remote_key=[ATTACKER_REMOTE_KEY]&amp;jwt=1&amp;client_id=[CLIENT_ID]&amp;lang=en&amp;return_skip=1</code><strong>) from the browser it launched, and send it to a victim? If they complete the OAuth login, will <em>my</em> <em>desktop app authenticate</em> <em>as them</em>?</strong>“ I decided to test this scenario.</p>
</blockquote>
<p>I logged out of my account, repeated the OAuth authentication flow, and copied the newly generated URL from the browser launched by the desktop application. I then used my phone as the victim device and opened the link there. To my surprise, the desktop application authenticated me as the victim.</p>
<p>Accordingly, the attack scenario can be illustrated as follows:</p>
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1764370923230/a21df537-ed9d-4111-ba76-013133db8b8e.png" alt="" style="display:block;margin:0 auto" />

<ol>
<li><p>The Attacker opens the <strong>Desktop Application</strong>.</p>
</li>
<li><p>The desktop app displays a <strong>login page</strong> with two options: Login with credentials and Login with OAuth.</p>
</li>
<li><p>The Attacker selects <strong>OAuth Login</strong>.</p>
</li>
<li><p>The desktop app launches the default browser and opens: <code>https://oauth2.redacted.com/auth/google?remote_key=[ATTACKER_REMOTE_KEY]&amp;jwt=1&amp;client_id=[CLIENT_ID]&amp;lang=en&amp;return_skip=1</code></p>
</li>
<li><p>Attacker Copies the URL and send it to the victim</p>
</li>
<li><p>Victim clicks on the link and browser will open</p>
</li>
<li><p>The browser shows the OAuth provider page. The victim completes the Google OAuth login.</p>
</li>
<li><p>After successful OAuth authentication, the browser redirects to the company website with a message: “<em><strong>Login completed, just close the browser.</strong></em>“</p>
</li>
<li><p>Meanwhile on the Attacker’s Side, right after starting the browser login, the <strong>Desktop App</strong> initiates a <strong>WebSocket connection</strong> to the backend server.</p>
</li>
<li><p>The Desktop App continuously checks the <strong>authentication status</strong> by sending the <code>remote_key</code> to the WebSocket Server in a loop, showing multiple cycles:</p>
<ul>
<li><p>Check #1 → server responds “<em>not authenticated</em>”</p>
</li>
<li><p>Check #2 → “<em>not authenticated</em>”</p>
</li>
<li><p>Check #3 → “<em>not authenticated</em>”</p>
</li>
</ul>
</li>
<li><p>Once the victim’s OAuth flow is completed, the server detects the session and sends a <strong>WebSocket response containing victim’s access token</strong>.</p>
<ul>
<li>Check #x → “<em>User Authenticated! (Access_Token: xxxxxxxx)</em>”</li>
</ul>
</li>
<li><p>On the attacker side The desktop app receives the <strong>access token</strong>, marks the attacker as authenticated, and logs them into victim account.</p>
</li>
</ol>
<p>As demonstrated, there were no mechanisms in place to verify whether the user authenticating on the desktop application was the same individual who was logged into the web session.</p>
<h2>Mitigation</h2>
<p>The root cause of this vulnerability lies in the absence of <strong>state validation</strong> between the OAuth initiator and the session completer. The <code>remote_key</code> parameter acts as a session identifier but lacks any binding to the device or user that generated it, allowing an attacker to hijack the authentication flow.</p>
<p>To address this vulnerability, the following mitigations should be implemented:</p>
<p><strong>1. Implement OAuth State Parameter</strong></p>
<p>The application should generate a cryptographically secure, random <code>state</code> parameter that is:</p>
<ul>
<li><p>Bound to the desktop application session</p>
</li>
<li><p>Validated upon OAuth callback</p>
</li>
<li><p>Single-use and expires after a short time window (e.g., 5 minutes)</p>
</li>
</ul>
<p>This ensures that only the entity that initiated the OAuth flow can complete it.</p>
<p><strong>2. Bind Remote Key to Device/Session</strong></p>
<p>The <code>remote_key</code> should be cryptographically tied to the desktop application's session or device identifier. When the WebSocket connection is established, the server should verify that:</p>
<ul>
<li><p>The <code>remote_key</code> was generated by the same device making the authentication request</p>
</li>
<li><p>The desktop app instance matches the one that initiated the flow</p>
</li>
</ul>
<p><strong>3. Add User Confirmation Step</strong></p>
<p>After the OAuth provider redirects back to the company website, it should display clear information about which device is requesting authentication:</p>
<ul>
<li><p>Device name/type</p>
</li>
<li><p>Approximate location</p>
</li>
<li><p>Timestamp of the request</p>
</li>
</ul>
<p>Require the user to explicitly confirm: “<em><strong>Are you trying to log in to [Device Name]?</strong></em>“ before sending the access token through the WebSocket.</p>
<p><strong>4. Implement Remote Key Expiration</strong></p>
<p>The <code>remote_key</code> should have a short lifespan (e.g., 2-3 minutes). If the OAuth flow is not completed within this timeframe, the key should be invalidated on the server side, and the desktop application should display a timeout error. This mechanism was implemented in this case, but this alone doesn't secure OAuth.</p>
<p><strong>5. Rate Limiting and Anomaly Detection</strong></p>
<p>Implement monitoring to detect suspicious patterns:</p>
<ul>
<li><p>Multiple failed authentication attempts with different <code>remote_key</code> values</p>
</li>
<li><p>Authentication requests from geographically distant locations within short time periods</p>
</li>
<li><p>Unusual WebSocket connection patterns</p>
</li>
</ul>
<p>By implementing these mitigations, the application can ensure that the OAuth authentication flow remains secure and that only the legitimate user who initiated the login process can complete it on their desktop application. <strong>Please note that mitigation steps 4 and 5 only make the attack more complex and will not secure OAuth on their own.</strong></p>
<h2><strong>Final Words</strong></h2>
<p>Don't hesitate to test cross-platform applications. Many security researchers avoid desktop or mobile apps because they seem <strong>complex</strong>, but take it easy and grow your <strong>mindset</strong>. You're a hacker! For a real hacker, there are no <strong>limitations</strong>. Approach cross-platform applications with curiosity and a willingness to investigate deeper layers. As you saw in this write-up, you should <strong>expand</strong> the attack surface as much as possible. Every application is like an <strong>iceberg</strong>; what you see is not all there is, so explore what's beneath the surface. After I reported this issue, the developer fixed it quickly. Once the initial report was marked as resolved, I decided to dig deeper into their new implementation and successfully bypassed the patch. In my next write-up, I’ll explain exactly how I did it and what went wrong with their fix.</p>
<p>I hope you enjoyed this write-up and found it helpful. See you in the next one!٫</p>
]]></content:encoded></item></channel></rss>