The redirect feature is often considered a small part of a website: users finish logging in and are directed to the dashboard, or after payment, they are returned to the confirmation page. The problem arises when the destination address is taken directly from the URL parameters without sufficient checks.
In such conditions, your website can be used to direct people to phishing sites. The link still uses a seemingly trustworthy domain, but once clicked, users are taken to another address controlled by the attacker. This is not just a matter of appearance. The reputation of the domain, notification emails, and login flows can also be misused.
What is meant by open redirect?
Open redirect is a condition when a website accepts a destination address from users and then performs a redirect without ensuring that the address is safe. A simple example is:
https://example.com/redirect?url=https://another-site.comIf that endpoint accepts the url value as is, anyone can change the address to a malicious site. Links like this are more convincing than regular phishing links because the beginning still uses the official domain.
The risks are not always about direct password theft. Open redirects can be used to make phishing campaigns appear more credible, disguise the link's destination in emails, or direct users to pages containing malware and scams.
Why are redirects often made too lenient?
The cause is usually not that developers intentionally ignore security. Redirects are built to meet reasonable needs: returning to the page before login, directing users to a chosen page, or saving the destination when the payment process is not yet complete.
The problem is that these needs are often translated into short code like this:
$url = $_GET['url'] ?? '/';
header('Location: ' . $url);
exit;This code simply shifts the responsibility to user input. The browser will follow the provided address as long as the format appears valid, including external addresses that were never intended by the website owner.
A safer pattern: use internal destinations
The safest option is not to accept complete URLs from users. Only store the names of destinations that the application already knows, then map those names to internal addresses.
$destinations = [
'dashboard' => '/dashboard',
'orders' => '/orders',
'profile' => '/profile'
];
$key = $_GET['to'] ?? 'dashboard';
$url = $destinations[$key] ?? '/';
header('Location: ' . $url, true, 302);
exit;With this pattern, users cannot change the destination to foreign domains. If the application's needs change, the list of destinations can be reviewed and tested as part of the code, rather than left open through URL parameters.
If you must accept URLs, restrict them tightly
There are cases when an application indeed needs to redirect users to external addresses, for example, after a payment process or when connecting to third-party services. In such situations, do not just check if the URL starts with https://. The checks should include the host, scheme, and URL format.
An example approach in PHP is to create a list of allowed domains:
$allowedHosts = [
'partner.example.com',
'payment.example.net'
];
$target = $_GET['url'] ?? '/';
$parts = parse_url($target);
$isAllowed = isset($parts['scheme'], $parts['host'])
&& $parts['scheme'] === 'https'
&& in_array(strtolower($parts['host']), $allowedHosts, true);
if (!$isAllowed) {
$target = '/';
}
header('Location: ' . $target, true, 302);
exit;Such validation still needs to be adjusted according to the application's architecture. Also, pay attention to variations in hostname, port, subdomain, and the possibility of using URLs with confusing formats. If the list of allowed domains can be made smaller, choose a smaller list.
Pay attention to redirects after login
Parameters like next, return, or redirect_to often appear in authentication flows. Their function is useful, but it becomes dangerous if those values can be filled with external URLs.
For login pages, a simple approach is to only accept local paths, not complete URLs:
$next = $_GET['next'] ?? '/dashboard';
if (
$next === '' ||
$next[0] !== '/' ||
str_starts_with($next, '//')
) {
$next = '/dashboard';
}The check for // is important because some browsers may interpret values like //phishing.example as external addresses. Remember that validation must be done on the server. Checks in JavaScript only help user experience, not serve as the main layer of security.
What about WordPress?
In WordPress, redirect risks can arise from plugins, themes, or custom code that processes URL parameters. Avoid sending user values directly to redirect functions.
Use WordPress's built-in validation functions when appropriate:
$redirect = isset($_GET['redirect_to'])
? wp_unslash($_GET['redirect_to'])
: home_url('/');
$redirect = wp_validate_redirect(
$redirect,
home_url('/')
);
wp_safe_redirect($redirect);
exit;wp_validate_redirect() helps ensure that the redirect destination does not go outside the list of allowed hosts in WordPress. wp_safe_redirect() is also designed for safer redirects. However, these functions are not an excuse to accept all input without understanding the flow of plugins or business needs.
What does this mean for us?
Open redirects often go unnoticed in simple scans because the website continues to function normally. There are no broken pages, no error messages, and legitimate users can still log in. The impact is only felt when the link is used in a scam campaign.
Therefore, security testing should not only check if redirects work but also whether redirects reject inappropriate destinations.
What you can do now
- Look for parameters with names like
url,next,return,redirect, orredirect_to. - Check if the values are sent directly to the
Locationheader or redirect functions. - Replace free URLs with an internal destination list if possible.
- If external destinations must be supported, use a narrow domain allowlist.
- Reject schemes other than HTTPS for external services.
- Test values like
https://example.org,//example.org, URLs with usernames, and similar hostnames. - Review plugins or libraries that handle login, payments, and third-party integrations.
Redirects may be a small feature, but they are at a point often overlooked by users. By limiting destinations and validating input on the server, websites not only become more technically secure but also harder to use for building false trust.
– Rio Yotto @rioyotto
