open-redirect

// TL;DR


What is an open redirect?

An open redirect is a flaw where a web page redirects to a URL taken from user-controlled input without properly validating it. Because the destination isn’t checked, an attacker can point it at any domain — which is valuable for phishing, since the link starts on a trusted site before bouncing the victim somewhere hostile.

The endpoint

I’d received an invitation to a private program on Bugcrowd and registered an account on the target (I’ll call it https://redacted.com). While poking around I hit a normal login endpoint with a redirect parameter:

https://redacted.com/login?nextUrl=url

The nextUrl value controls where you land after logging in — a classic open-redirect candidate.

The clue: concatenation, not validation

I tried the standard payloads first — nextUrl=http://evil.com, nextUrl=//evil.com, and the usual variants. All rejected. So far it looked properly defended.

Then, almost idly, I put a bare evil.com in the parameter:

https://redacted.com/login?nextUrl=evil.com

…and after login the destination became:

https://redacted.comevil.com

That was the tell. The app wasn’t validating my input — it was concatenating it directly onto its own domain. Seeing redacted.com + evil.com glued together told me exactly what to do next: supply a character that turns that concatenation into a valid redirect off-site.

The bypass payloads

Two small payloads did it, each abusing URL parsing:

Leading dot — nextUrl=.evil.com:

https://redacted.com.evil.com

redacted.com.evil.com is a subdomain of evil.com, fully attacker-controlled. (Worked in Firefox.)

The @ trick — nextUrl=@evil.com:

https://redacted.com@evil.com  →  evil.com

Everything before the @ in a URL is treated as credentials (userinfo), so redacted.com becomes a username and the browser navigates to evil.com. (Worked in Chrome.)

Either way, a link that begins with the trusted redacted.com sends the victim to the attacker’s domain — exactly the trust-borrowing an open redirect is dangerous for.

Duplicate → re-review → bypass

The triage part is worth sharing, because it’s a lesson in itself. Within about two minutes of reporting, my submission was auto-closed as a duplicate of an older report (an open redirect on the same nextUrl parameter, filed a year earlier).

I checked the referenced report’s PoC — and it no longer worked. The original had been fixed. So I asked the team to re-review: if the old one was resolved and mine still worked, mine wasn’t a duplicate — it was a bypass of their fix. They re-opened it, agreed, and rewarded a $200 bounty.

redirect-bounty

or-bounty

I’ve since found open redirects many times with this same concatenation-based technique.

Takeaways

  • When the obvious payloads fail, learn how your input is handled. The breakthrough wasn’t a payload — it was noticing the app concatenated my value onto its domain. A single harmless test (evil.com) revealed the mental model I needed.
  • . and @ are open-redirect workhorses. A leading dot turns the trusted host into a subdomain of your domain; an @ turns it into userinfo and sends the browser to yours. Try both — they often behave differently across browsers.
  • Don’t accept a “duplicate” at face value. If the referenced report is already fixed and your PoC still fires, you’ve found a bypass, which is a new, valid finding. Politely request a re-review with that reasoning.
  • A fixed bug is a great place to look. Patches are often incomplete. Re-testing resolved reports for bypasses is one of the higher-yield habits in bug bounty.

Thanks for reading — hope it was useful. Happy hacking!

Anas Mahmood

Web & API penetration tester and bug bounty hunter. I write up the bugs I find and the methods that found them.

Leave a Reply

Your email address will not be published. Required fields are marked *