Skip to content

WordPress site redirecting to another site: how to tell a hack from a setting, and what to do first

A redirect to a site you did not choose is a sign of a hacked WordPress, but a redirect rule, the site address settings, an expired domain or the visitor's own device can look the same. Check what a visitor is served, look where redirects are planted, and delete nothing until you have a copy.

By
WP Ministry
Published

In short

  • A redirect that only visitors from Google or only phones get is the pattern Google's documentation describes for a hacked site.
  • Rule out four ordinary causes first. They are the site address settings, a redirect you or a plugin set, the domain or its DNS, and an ad or an extension on the visitor's device.
  • Do not test in your own browser. Ask for the page with curl, once plainly, once as a visitor from Google and once as a phone.
  • The checksum commands cover WordPress's own files and plugins from WordPress.org. They do not cover .htaccess, wp-config.php, themes or the database.
  • Do not delete the rule or the file you find. Write it down, take a copy of the site, then follow the full cleanup.
  • Removing one redirect is not a cleanup. If the way in stays open, or a backdoor is left behind, it comes back.

Visitors being sent to a site you did not choose is a recognized sign that a WordPress site has been broken into. Google lists redirects among its examples of hacked content. Four ordinary things look the same: the site address settings, a redirect that you or a plugin set, an expired domain or changed DNS, and an ad or a browser extension on the visitor's own device.

Tell them apart before you touch anything. None of the checks on this page changes the site, and what you find is evidence you will want later.

Is it a hack or something else?

Start with who is redirected and where they land.

What you seeWhat it points to
Visitors who click a result in Google are sent away. Typing the address shows your site.A hack. Google's spam policies give this as their example of a hacked redirect.
Only phones are redirected.A hack, or an ad script. Google's Search team has described both.
It happens to a visitor once and not again, or never while you are logged in.A rule that picks its visitors, which is how a planted redirect behaves.
Google Search Console lists a security issue for the site.Google has found it. Its report gives redirects to a malicious site as an example of code injection.
Everyone is sent to an address you recognize: an old domain, a staging copy, the same site with or without www.The site address settings, or a redirect that you, a developer or a plugin set.
Everyone lands on a registrar's page that says the domain has expired.The domain's registration, not WordPress.
One person is redirected, on one device, and it happens to them on other sites too.Unwanted software or an extension on that device.
The browser shows ERR_TOO_MANY_REDIRECTS and reaches no page at all.A loop between your own addresses. That is a different problem, and how to fix ERR_TOO_MANY_REDIRECTS covers it.

A planted redirect is choosy on purpose. Google's guidance for hacked sites says hackers may serve their content only to certain referrers or user agents, to reach more real visitors and to avoid detection by site owners and malware scanners. Google's documentation lists the referrer, the user agent, the device and the time of day as conditions. A rule on the server can also read cookies, and WordPress marks a logged-in browser with one. So the owner can be the one person who never sees it.

Rule out the four ordinary causes

  • The site address settings. In the dashboard, go to Settings, then General. "WordPress Address (URL)" and "Site Address (URL)" should both hold your own address. WordPress writes the address stored there into every link, stylesheet and script on the page, sends the login and the dashboard to it, and redirects between the www and plain forms of an address. So with a wrong value the first page may still load, and a visitor lands on the other address at the first click. If the value is an old or a staging address of yours, how to change your WordPress URL has the fix. A domain you have never seen is not an ordinary cause: someone changed it.
  • A redirect that you or a plugin set. Look through your redirect plugin's list and through the rules in .htaccess. How to set up redirects in WordPress shows the three places a redirect can live. A rule nobody on your side can account for is not an ordinary cause either. Leave it in place and keep reading.
  • The domain. Log in at your registrar. Check the renewal date, and that the nameservers and records are the ones your host gave you. Under ICANN's policy for expired registrations, a registrar that sends an expired domain's visitors to a web page must make that page say the registration has expired and give renewal instructions.
  • An ad, or the visitor's own device. Chrome's help lists browsing that "redirects to unfamiliar pages or ads" among the signs of unwanted software on a computer, so ask the person who reported it whether it happens on other sites. On your side, Google's Search team notes that a script installed to show ads can send phone visitors to a different site without the owner being aware. Its advice is to check for a hack first. If there is none, remove the third-party scripts you do not control one at a time, and check on a phone between each.

See what a visitor is served, without logging in

  1. Step 1: Ask for the page four ways

    Run these in a terminal on your own computer, with your own address. The first asks plainly. The second says it arrived from Google. The third says it is Chrome on an Android phone. The fourth says both. Then run them again with the address of a post or a product, which is where a visitor from search lands.

    bash
    curl -s -o direct.html -w "%{response_code} %{redirect_url}\n" https://example.com/
    curl -s -o from-search.html -w "%{response_code} %{redirect_url}\n" --referer "https://www.google.com/" https://example.com/
    curl -s -o phone.html -w "%{response_code} %{redirect_url}\n" --user-agent "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Mobile Safari/537.36" https://example.com/
    curl -s -o phone-from-search.html -w "%{response_code} %{redirect_url}\n" --referer "https://www.google.com/" --user-agent "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Mobile Safari/537.36" https://example.com/
  2. Step 2: Read the four lines

    Each command prints the status code and, for a redirect, the address it leads to. It also saves the page to a file. 200 with nothing after it means the page was served. 301 or 302 followed by your own address, with https or www added, is your site's normal behavior. An address on a domain that is not yours is a positive result. So is a redirect that shows on some of the four lines and not on others.

  3. Step 3: See what sent the redirect

    If a line showed a redirect, repeat that request with -D -, which prints the response's headers. The Location line names the destination. A line that begins X-Redirect-By means the redirect went through WordPress's own redirect function, which adds that header and says WordPress unless a plugin puts its own name there. That points at the address settings, a plugin or the theme. With no such line, the redirect came from somewhere else: a server rule such as one in .htaccess, or PHP code that does not use WordPress's function.

    bash
    curl -s -o from-search.html -D - --referer "https://www.google.com/" https://example.com/
  4. Step 4: Look in the saved pages for scripts you did not add

    Not every redirect shows in the status code. Google's guidance shows a script that reads where the visitor came from and then sends the browser elsewhere. curl runs no scripts, so that page saves with a 200. This lists every script tag in a saved page. Each address in the list should be one you can name: your own domain, your analytics, your ad network. Then open the file in a text editor and search for the words Google suggests: iframe, eval and unescape.

    bash
    grep -o '<script[^>]*>' phone-from-search.html
  5. Step 5: Run the two checks that need no terminal

    The redirect checker follows an address hop by hop from our server, with no cookies and nothing remembered. The hacked-site check asks for a page twice, once plainly and once as a visitor from a search result, and compares where each ends. Neither presents itself as a phone.

  6. Step 6: Check Google's Safe Browsing site status

    Enter your address on Google's site status page. It says whether the site currently contains content that Safe Browsing has determined to be dangerous.

  7. Step 7: Open the Security issues report in Search Console

    The report shows what Google has found, with sample addresses. If your site is not in Search Console yet, add it first. Google's help says you may not be able to reproduce a warning yourself, and to rely on the report as the source of truth.

A clean result from all of these does not clear the site. Nobody outside can imitate a rule that goes by the time of day or by the visitor's network address. If visitors keep reporting it, look inside.

Where a planted redirect lives

WordPress's documentation for hacked sites names .htaccess as the one file you will definitely want to look at. It lists index.php, header.php, footer.php and the theme's functions file as files that affect every page request when modified. Google's guidance adds the server's configuration, the database, and code injected into pages.

The steps below go through those places. They need SSH access and WP-CLI, and most say what to open if you have neither. Look, and change nothing. Write down each thing you find, where it is, and the time.

  1. Step 1: Run the two checksum commands

    The first compares every file of WordPress itself, the main index.php included, with the checksums WordPress.org holds for your version. With --include-root it also warns about files in the main folder that are not part of WordPress. The second does the same for each plugin that came from WordPress.org. Clean runs print "Success: WordPress installation verifies against checksums." and "Success: Verified" with a count, and nothing else. Any Warning: line is a finding, even when the last line says Success: a file that was added, with no original changed, is reported as "File should not exist" and the command still ends in Success.

    Neither command checks .htaccess, wp-config.php, any theme, the uploads folder or the database. A plugin that did not come from WordPress.org is skipped with a warning, and WP-CLI has no checksum command for themes. So a clean result here clears two places and leaves the rest of this list.

    bash
    wp core verify-checksums --include-root
    wp plugin verify-checksums --all --skip-plugins --skip-themes
  2. Step 2: Read every .htaccess file

    .htaccess is Apache's configuration file for one folder, and there can be one in any folder. List them all and open each. In a file manager, turn on hidden files first, or you will not see them. A clean one in the main folder holds the block WordPress writes between # BEGIN WordPress and # END WordPress, shown in how to fix the 403 Forbidden error, plus rules that you, your host or a plugin can account for.

    Google's example of a planted rule is a RewriteCond line that tests %{HTTP_REFERER} for Google, followed by a RewriteRule that ends in another site's address and [R=301]. Look also for conditions on %{HTTP_USER_AGENT} or %{HTTP_COOKIE}, and for an ErrorDocument line that names another site. On nginx there is no .htaccess. Its rules sit in the server's own configuration, so ask your host to read it.

    bash
    find . -name ".htaccess"
  3. Step 3: Open index.php and wp-config.php

    The checksum command has already compared index.php. A clean one is a few lines: it sets WP_USE_THEMES and loads wp-blog-header.php.

    wp-config.php has no checksum, because every site's is different. Compare it with wp-config-sample.php from a fresh download of WordPress. The sample holds the database settings, eight keys and salts, the table prefix, WP_DEBUG, and closing lines that set ABSPATH and load wp-settings.php. Yours will hold more, from your host and your plugins, and each line should be one somebody can explain. The command below prints the lines to read first: an address set with WP_HOME or WP_SITEURL, any file being loaded, and code passed to eval. The line that loads wp-settings.php belongs there.

    bash
    grep -n -E "WP_HOME|WP_SITEURL|include|require|eval|base64_decode" wp-config.php
  4. Step 4: Check the two address settings

    These print the two addresses WordPress is using. Both should be your own. A WP_HOME or WP_SITEURL line in wp-config.php overrides the stored value, and is what prints here when one is set. Without WP-CLI, they are the two fields under Settings, then General. If a wrong address keeps you out of the dashboard, write it down. How to change your WordPress URL shows how to get back in.

    bash
    wp option get home --skip-plugins --skip-themes
    wp option get siteurl --skip-plugins --skip-themes
  5. Step 5: List the must-use plugins and drop-ins

    Must-use plugins are PHP files in wp-content/mu-plugins. They are always on, cannot be switched off from the dashboard, and are not in the default list on the Plugins screen. Drop-ins are files with fixed names placed straight in wp-content, such as advanced-cache.php, object-cache.php and db.php. Hosts commonly use must-use plugins, and a caching plugin may add a drop-in. A clean list is short, or empty, and every entry is one your host or a plugin of yours accounts for. Without WP-CLI, open wp-content and wp-content/mu-plugins in your host's file manager.

    bash
    wp plugin list --status=must-use --skip-plugins --skip-themes
    wp plugin list --status=dropin --skip-plugins --skip-themes
  6. Step 6: Read the active theme's files

    The list shows which theme is active and, for a child theme, which is its parent. WordPress runs the functions file of both. Open functions.php, header.php and footer.php in each theme's folder under wp-content/themes. A block theme has header.html and footer.html template parts in place of the last two.

    The only clean original is a fresh copy of the same version from where the theme came, so compare against that. Without one, read for the patterns Google's guidance shows: a script tag that loads from a domain you do not know, an iframe with no height or width, a script that tests document.referrer and then sets the location, and a long unreadable string passed to eval.

    bash
    wp theme list --skip-plugins --skip-themes
  7. Step 7: Search posts, widgets and settings for scripts

    This searches every text column of WordPress's tables and prints the table, the column, the row and the text around each match. Posts show under post_content. Widgets and settings show under option_value. WordPress lets administrators and editors put JavaScript in posts, pages and widgets, so a match is not a finding by itself. A clean result is no match, or matches you can name, such as an embed you pasted. Run it again for <iframe. Without WP-CLI, use the search in a database tool such as phpMyAdmin.

    bash
    wp db search "<script" --table_column_once --skip-plugins --skip-themes
  8. Step 8: List the administrators

    WordPress's documentation gives a user nobody created as a clear sign of a hack. Every name here should be a person you can account for, with their own email address. Without WP-CLI, open the Users screen and select the Administrator link above the table.

    bash
    wp user list --role=administrator --fields=ID,user_login,user_email,user_registered --skip-plugins --skip-themes

These steps cover where a redirect is planted. How to check whether your WordPress site has been hacked covers the wider checks: the uploads folder, scheduled events, recently changed files and the access log.

What to do now

If the checks pointed at an ordinary cause, fix that one thing: the address, the redirect, the domain or the script. Then run the four curl requests again. If they pointed at a hack, or you cannot tell, do these in order.

  1. Step 1: Leave what you found where it is

    Do not delete the rule, the file or the user. The site as it stands is the record of what was done to it, and deleting the one thing you can see leaves the things you cannot. Keep your notes and the files curl saved.

  2. Step 2: Follow the runbook for the first hour

    The hacked site runbook has the order: have the host take the site offline for the public if it is harming visitors, take a full copy of the files and the database, then change the passwords and the secret keys. Take the copy before any cleaning.

  3. Step 3: Then do the full cleanup

    How to remove malware from a hacked WordPress site has the steps: restore a backup from before the break-in, or replace everything that has a clean original and check the rest by hand. It also covers finding the way in.

Get help when the redirect comes back after you removed it, when you find code you cannot read, or when the site takes orders or holds customer accounts. Our malware removal service is a one-time clean-up with hardening, a blacklist removal request and a written report.

After it is clean

Why the redirect comes back

  • Something was left behind. Google's guidance warns that a hacker may leave "back doors" that allow re-entry, or that put back the malicious code you removed. It also says that if an infected file remains on the server, the site is more likely to be hacked again.
  • The way in is still open. Google lists the usual ones: a virus on an administrator's computer, weak or reused passwords, out-of-date software, and permissive code. It adds that there may be several independent hacks in place, so finding one hole is not a reason to stop looking.

WordPress's documentation ends its own list the same way: update everything, and change every password again once the site is clean.

Ask Google for a review if the site was flagged

Cleaning the site does not lift a warning by itself. Google says you must request a review to have a site unflagged. If the Security issues report lists an issue, fix it on every page, not only on the sample addresses, then select "Request Review" in the report. Google asks that the request explain the exact issue, describe the steps you took and document the outcome.

Google says most reviews take several days or weeks, and that you are emailed when one is complete. Do not send a second request while the first is open. Google's help warns that asking before the issue is fixed can lengthen the next review, or get the site marked as a repeat offender. If the report shows no issue, there is nothing to request.

Common questions

Why does the redirect only happen on phones, or only from Google?

Because the rule was written that way. Google's spam policies describe hacked redirects that depend on the referrer, the user agent or the device, and its guidance for hacked sites says the aim is to reach real visitors while avoiding detection by the site's owner. A redirect that only phones get can also come from an ad script, so check the Security issues report first.

A visitor says they were redirected, and I cannot see it. Who is right?

Possibly both. A planted redirect can leave out anyone who typed the address, anyone not on a phone and anyone who is logged in. Run the four curl requests on this page before deciding. If they are clean and only one person reports it, ask whether it happens to them on other sites, which points at their own device.

Can I delete the bad line from .htaccess and be done?

That stops this redirect and settles nothing else. Whoever added the line could write to your files, and Google's guidance warns of back doors that put removed code back. Take a copy of the site first, then do the full cleanup and find the way in.

I cleaned the site and I am still redirected. Is it back?

Check with curl or the redirect checker before deciding. A 301 is a permanent redirect, and a browser is allowed to store one and keep following it without asking your site again. Both tools ask fresh. If they show the redirect too, it is back.

More on this subject

Malware removal, done for you

Malware removal is $99. Full clean-up, hardening, blacklist removal request and a written report. 30-day re-clean guarantee. It starts with a free diagnosis.