Example finding How it works Coverage PENTEST METHODOLOGY DOCS PRICING FAQ MCP CONTACT LOG IN SIGN UP →

OAuth redirect URI wildcard: the risk and how to fix it

FIX / OAUTH REDIRECT URI / 9 MIN READ

A wildcard in an OAuth redirect URI lets an attacker choose where your login code goes. Replace every wildcard with the exact callback URLs of your app. The code or token then goes to the attacker. The attacker uses it to sign in as the victim. The fix takes about 15 minutes.

This guide explains the risk in plain steps. It shows how to find wildcards in your provider and your auth settings. It then gives the fix, the checks for damage, and the way to stop it from coming back.

What is the risk of an OAuth redirect URI wildcard?

The redirect URI is the address that the provider uses after the user signs in. The provider adds a login code or a token to that address. The browser then opens the address, and your app reads the code.

The provider keeps a list of allowed addresses. The provider checks each login request against this list. If the request has an address that is not on the list, the provider refuses it.

A wildcard makes the list wider. The entry https://*.example.com/* does not name one address. It names a large set of addresses. If an attacker controls one address in that set, the attacker receives the code.

The OAuth security best practice gives the rule. The OAuth 2.0 Security Best Current Practice (RFC 9700) says that the authorization server must make sure that the two URIs are equal. Its section 4.1 shows how a pattern such as https://*.somesite.example/* can be misused. This means exact string matching is the correct setting.

Vibe coding tools often add wildcards. You ask for working login on a preview URL, a local server, and production. The tool adds a broad pattern so that all three work. The login works, so nothing shows that the list is too wide.

How does the attack work?

The attacker needs two things. The first is a way to make the provider send the code to an address that the attacker controls or can read. The second is a victim who opens a crafted login link.

The attack has these steps:

  1. The attacker finds that your allow list has a wildcard, such as https://*.example.com/*.
  2. The attacker finds an address that matches the wildcard and that the attacker controls or can use. Examples are a forgotten subdomain, a user-content page, or a page on your site that redirects to another site.
  3. The attacker builds a login link. The link sets the redirect_uri parameter to that address.
  4. The victim opens the link and signs in. The victim often sees a normal provider page and a normal consent step.
  5. The provider sends the login code to the address of the attacker.
  6. The attacker exchanges the code for a session, or reads the token, and acts as the victim.

Step 2 is the weak point. The RFC describes the case with an open redirector. A page on your site accepts a next parameter and sends the visitor to that address. A wide pattern matches that page. The provider sends the code to your page, and your page sends the visitor, with the code, to the attacker. For tokens in the URL fragment, the RFC says the browser adds the fragment to the new address, so the attacker page can read it.

Subdomain wildcards have a second risk. A DNS record that points to a deleted service can let an attacker claim that subdomain. See S3 and subdomain takeover for that problem. A wildcard on the domain then covers the claimed subdomain.

How do I confirm that my app has a wildcard redirect?

Check three places. Each place holds a list of allowed addresses.

Check the OAuth provider

Open the OAuth app settings at each provider that you use. Read every entry in the list of redirect URIs.

  • Google. The Google OAuth documentation says that redirect URIs cannot contain wildcard characters (*). If you see a wildcard here, the console should have refused it. Check the other entries for paths that are too wide.
  • GitHub. The GitHub OAuth documentation says that the redirect URL must match the host and the port of the callback URL. It also says that the path must be a subdirectory of the callback URL. So a callback URL of https://example.com/ accepts every path on that host. Set the callback URL to the full callback path.

Check your auth service

Open the URL configuration of your auth service. In Supabase this is the URL Configuration page in the dashboard. The Supabase redirect URLs documentation says that you can use wildcards in the allow list. It also says to set the exact redirect URL path for your site in production.

Look for these entries:

Entry Problem
https://*.example.com/** Matches every subdomain and every path.
https://example.com/** Matches every path, including any redirect page.
https://*.vercel.app/** Matches the apps of every Vercel user.
http://localhost:3000/** in production Allows a code to go to a local server.
Site URL set to http://localhost:3000 The default address after login is a local server.

The fourth row is the most common. Anyone on a shared network, or any program on a victim computer, can run a server on port 3000. Remove local addresses from the production project.

Test the login flow

Do a live test. Use a test account.

  1. Start a normal login in the browser. Open the DevTools Network tab before you click the login button.
  2. Find the request to the provider. Copy the full URL.
  3. Change the redirect_uri value to https://example.org/callback. Use an address that is not in your list.
  4. Open the changed URL.

The provider must show an error such as redirect_uri_mismatch. If the provider accepts the address, the list is too wide. Test a second address on a sibling subdomain of your own domain. Then test an address that is only a different path on your own domain.

For services that take the redirect value from your code, such as the redirectTo option in Supabase, test that value too. Call the sign-in function with a foreign address and read where the browser goes next. If the service accepts it, the service allow list is too wide.

How do I fix a wildcard redirect URI now?

Do the steps in this order. Steps 1 to 3 close the gap. The other steps reduce the risk.

Caution: Logins break for any address that you remove and still use. Make a list of the real addresses before you start. Test each address after the change.

  1. Write down the real callback URLs. Include production, staging, and local development. Write the full URL with the path, such as https://app.example.com/auth/callback.
  2. Replace each wildcard in the auth service with exact URLs. Delete ** and * entries. Add one entry for each real URL.
  3. Replace each wide entry at the provider. Use the full callback path. Remove any entry that you do not use.
  4. Set the Site URL to production. In Supabase, the Site URL is the default address when your code gives no redirectTo. Change it from http://localhost:3000 to your production address.
  5. Remove local addresses from the production project. Use a separate project for local development.
  6. Fix open redirects on your own domain. Search your code for parameters named next, redirect, returnTo, and url. Accept only a path that starts with / and not with //. See SSRF, open redirect, and OAuth for the patterns.
  7. Turn on PKCE for the flow. PKCE binds the code to a secret that only your app holds. The Supabase client libraries use PKCE for server-side and mobile flows. Check the setting in the documentation of your client library.
  8. Rotate the client secret if you think that someone used the gap. Create a new secret at the provider. Put it in the server-side settings of your auth service. Delete the old secret.

An exact allow list for a production project looks like this:

https://app.example.com/auth/callback
https://app.example.com/auth/confirm

An allow list for a staging project can add the local address:

https://staging.example.com/auth/callback
http://localhost:3000/auth/callback

Do not put the staging list and the production list in the same project.

What if I need preview URLs?

Preview URLs change with each deployment, so exact entries do not work. Many teams then add a wildcard. This is the case where a wildcard has a reason. Use these rules to limit the risk:

  • Use a separate auth project for previews. Do not connect it to real user data.
  • Make the wildcard as narrow as possible. Include your team name or your project name in the pattern. Do not use a pattern that any other account can match.
  • Keep the path exact. Use /auth/callback, not /**.

The Supabase documentation says that wildcards are for preview URLs on services such as Vercel and Netlify. It also says that ** is useful for local development and previews. It does not recommend them for production.

An alternative is a fixed preview address. Some hosts let you set one alias for the latest preview. One exact entry then covers all previews.

How do I check for damage?

Read the logs for the time since the wildcard first existed. You cannot always know that date. Use the date of the first deployment of the auth settings if you are not sure.

  1. Read the auth logs. In the Supabase dashboard, open the logs for Auth. Look for sign-ins that come from an unusual country, or at an unusual time. Look for sign-ins to accounts that do not normally sign in.
  2. Read the provider logs. Some providers show sign-in activity for the OAuth app. Check Google Cloud and the GitHub app settings for authorized users and for recent activity.
  3. List recent sessions. Sort your users by the last sign-in date. Find users whose last sign-in does not match the user’s own report.
  4. Search your web logs. Search the logs of your host for requests to your callback path with a code parameter and an unexpected Referer or user agent. Search for requests to your redirect pages with a foreign address in the query string.
  5. Check privileged accounts first. Check admin and owner accounts. A taken-over admin account has the largest effect.

If you find a sign-in that you cannot explain, do these things:

  1. Revoke the sessions of that user. Make the user sign in again.
  2. Rotate the OAuth client secret.
  3. Ask the user to review the account for changes in email, password, and connected apps.
  4. Check the data that the account could read or change.

A missing sign-in record does not prove that no attack happened. If the wildcard was wide for a long time, rotate the client secret anyway.

How do I stop it from coming back?

Use controls that do not depend on a person remembering a rule.

  • Keep the allow list in code. For Supabase, you can store the redirect URLs in the project configuration file and apply it from the repository. A change then appears in a code review. Check the Supabase CLI documentation for the setting names in your version.
  • Add a test. Write a test that starts a login with a foreign redirect_uri and expects an error. Run the test after each deployment.
  • Use exact matching in your own code. If your app builds a redirect from user input, compare the full string with a fixed list. Do not use startsWith or includes on the host. A host such as example.com.attacker.example passes both checks.
  • Review AI-written auth changes. When a coding tool changes login, read the diff for the allow list. Look for *, **, and localhost.
  • Keep one project for each environment. Production, staging, and previews then have different lists.
  • Use PKCE and short code lifetimes. These controls reduce the value of a stolen code.

For the wider checks on login flows, see auth flows: magic links, OTP, and reset and cookie, TLS, and OAuth PKCE gaps.

When should I ask for help?

Ask a security professional for help in these cases:

  • You find sign-ins that you cannot explain, and the accounts hold personal or payment data.
  • An admin account changed without the owner knowing.
  • You have open redirects and you cannot tell which pages are affected.
  • Your app uses OAuth for access to the data of users at a third party, such as email or files.
  • You must tell users or a regulator about a possible breach and you do not know the rules that apply to you.

Keep the logs and a list of your changes. Save a copy of the old settings before you delete them.

Common questions

Is a wildcard in a redirect URI always unsafe?
No, but it is always weaker than an exact URL. A wildcard is safe only when every URL that it matches is under your control. Use exact URLs for production.
Does a wildcard on the path matter if the domain is mine?
Yes. A wide path pattern can match a page on your domain that redirects to another site. That page gives the attacker the login code.
Do I need PKCE if I use exact redirect URLs?
Yes, use both. Exact URLs stop the code from going to a wrong place. PKCE makes a stolen code useless without the secret that your app created.
Can I use a wildcard for Vercel or Netlify preview URLs?
Do it only on a separate staging project that has no real user data. Keep the production project on exact URLs.
How do I know if someone already used my wildcard?
Read the auth logs of your provider for sign-ins that you cannot match to a user. Then revoke sessions and rotate the client secret.

Test your login redirects

A VibeEval scan checks the login flow of your deployed app and reports redirect URL settings that accept a URL you did not intend.

14-day free trial · No credit card · Cancel anytime

SCAN YOUR APP →