Skip to content

How to Fix a WordPress Redirect Hack (And Keep It Gone)

To fix a WordPress redirect hack, check siteurl and home in wp_options, search the database and filesystem for injected JavaScript and obfuscated PHP, verify core and plugin checksums, and remove rogue admin users, cron events, and fake plugins. Then patch the vulnerable plugin that let the attacker in, or the redirect returns within days.

How to Fix a WordPress Redirect Hack (And Keep It Gone)

Why You Cannot Reproduce the Redirect (And the Attacker Wants It That Way)

A wordpress redirect hack is malicious code that sends your visitors somewhere else, usually a fake browser update, a push notification scam, a gambling page, or a fake dating site. You hear about it from customers but cannot see it yourself because the payload checks who is visiting before it fires.

Most variants I clean skip logged-in users, skip anyone who typed the URL directly, and drop a cookie so each visitor only gets redirected once. Sucuri documented a January 2025 sample injected into a theme’s functions.php that did all three, filtered out search engine crawlers by user agent, and hid its destination behind hex-escaped strings like \x68\x74\x74\x70s. The Sign1 campaign went further and only fired when the referrer was Google, Facebook, Instagram, or Yahoo.


So before you touch anything, reproduce it the way a victim sees it: private window on your phone, Google search for your site, tap the result, browse a few pages. If that redirects and a logged-in desktop visit does not, you have conditional redirect malware, not a misconfigured plugin.

Where does redirect malware hide in WordPress?

A wordpress redirect hack lives in one of nine places, and a real cleanup checks all nine. Sucuri’s 2024 SiteCheck data shows the biggest campaigns (Balada Injector at 149,351 detections, Sign1 at 96,084) storing payloads in database options, custom HTML widgets, theme files, and snippets inside legitimate plugins like WPCode and Simple Custom CSS and JS, precisely because file scanners miss the database and database scanners miss the files.

Hiding place What the infection looks like Detection command
wp_options siteurl / home Both options changed to an attacker domain or a script URL wp option get siteurl && wp option get home
Other wp_options rows Autoloaded option holding base64 or hex-escaped JavaScript wp db query "SELECT option_name FROM wp_options WHERE option_value LIKE '%eval(%' OR option_value LIKE '%atob(%' OR option_value LIKE '%fromCharCode%'"
wp_posts post_content Script tag appended to every post or page wp db query "SELECT ID FROM wp_posts WHERE post_content LIKE '%script%src=%' AND post_status='publish'"
WPCode or code snippet plugins PHP snippet stored as post_type wpcode, hidden from the admin menu wp post list --post_type=wpcode --fields=ID,post_title,post_status
Custom HTML and block widgets Obfuscated JS in widget_custom_html or widget_block wp option get widget_custom_html --format=json
.htaccess and nginx config RewriteCond on user agent or referrer sending traffic offsite find . -name .htaccess -newer wp-settings.php
Theme header.php / functions.php Injected block at top or bottom, often after a long run of blank lines grep -rl -e "eval(" -e "base64_decode" -e "str_rot13" wp-content/themes/
Fake plugins and mu-plugins Innocent name (hello.php, wp-cache-manager) that loads on every request ls -la wp-content/mu-plugins/ && wp plugin list --status=active
Rogue admin users and cron events New administrator, or a scheduled hook that rewrites files wp user list --role=administrator && wp cron event list

I run every row of that table on every redirect job, even when the first hit looks obvious. Fixing siteurl and stopping there is how a site lands back in your inbox next week.

Contain It Before You Clean It

Snapshot the infected site first, then rotate credentials, then restrict public access. You need the infected copy for forensics: file modification times and the exact injected strings tell you where the attacker got in.

Rotate everything the attacker could have captured: admin passwords, the database password in wp-config.php, SFTP and hosting logins, and the salts (wp config shuffle-salts regenerates them and logs every session out). Then put the site behind maintenance mode or an IP allow rule while you work.

The general containment playbook is covered in more depth in our guide to fixing a hacked WordPress site. The rest of this post assumes you have done that and are now hunting the redirect specifically.

Step 1: Verify Core and Plugin Files Against Official Checksums

Start with the two commands that eliminate the most files fastest. WP-CLI compares core and every wordpress.org plugin against official checksums for the installed versions and lists anything modified or added.

wp core verify-checksums
wp plugin verify-checksums --all

Modified core files (wp-blog-header.php, index.php, the bundled jquery.min.js) are a common carrier because they load on every request. The Balada Injector wave that hit Popup Builder sites used wp-blog-header.php as its secondary injection point alongside a database payload.

Two gaps. Premium plugins and all themes are not on wordpress.org, so verify-checksums cannot vouch for them; compare those against a fresh vendor download. And mu-plugins are never checked, which is exactly why campaigns like DollyWay drop small fake plugins there.

Step 2: Search the Database Row by Row

Check siteurl and home first, then hunt for injected JavaScript in posts, options, and widgets. The two URL options are the fastest fix and the fastest reinfection, so I check them before anything else.

wp option get siteurl
wp option get home

If either returns anything other than your domain, set it back with wp option update siteurl https://yourdomain.com and keep going, because whatever wrote it is still on the server. Next, dry-run a search for the attacker’s domain (grab it from the redirect chain in your phone test) across every table:

wp search-replace 'evil-domain.top' 'REMOVED' --dry-run --all-tables

The dry run reports how many rows in which tables reference the domain without changing anything: one tampered option or thousands of injected posts. When you are confident, snapshot, drop the --dry-run flag, and run it for real.

Then check the places file scanners never look:

  • WPCode snippets: wp post list --post_type=wpcode --fields=ID,post_title,post_status. WPCode registers its own post type, so PHP snippets sit in wp_posts and execute on load. Attackers add a snippet and hide the WPCode menu with a CSS rule.
  • Custom HTML widgets: wp option get widget_custom_html --format=json and wp option get widget_block --format=json. Sign1 lived almost entirely here.
  • Autoloaded junk: wp option list --autoload=on --fields=option_name,size_bytes. A 40KB option you do not recognize deserves a look.

Bloated tables slow this down; a pass through the WordPress database maintenance walkthrough first shrinks the haystack.

Step 3: Grep the Filesystem for Obfuscation Signatures

Search for the encoding functions attackers rely on, then search by modification time. Obfuscated PHP almost always calls one of a small set of functions, and injected JavaScript almost always decodes itself with atob or String.fromCharCode.

grep -rlE "eval\(|base64_decode\(|gzinflate\(|str_rot13\(|gzuncompress\(" wp-content/ wp-config.php
grep -rlE "atob\(|fromCharCode|\\\\x[0-9a-f]{2}\\\\x[0-9a-f]{2}" wp-content/themes/ wp-content/uploads/
find . -name "*.php" -mtime -30 -not -path "./wp-content/cache/*"
find wp-content/uploads/ -name "*.php"

Expect false positives from plugins that use base64_decode legitimately. What you want is eval wrapped around a decode, a long single-line string at the top of functions.php, or any PHP file at all inside uploads.

Redirect rules also live in web server config, which grep for PHP functions will not catch. Audit every .htaccess (attackers nest them in subdirectories) and, on nginx, the server block:

find . -name ".htaccess" -exec sh -c 'echo "== $1"; cat "$1"' _ {} \;

A malicious .htaccess redirect typically checks HTTP_USER_AGENT for mobile strings or HTTP_REFERER for google, then issues a 301 to an external URL. Any RewriteRule pointing to a domain you do not own goes.

Step 4: Remove Users, Cron Jobs, and the Backdoor That Feeds Them

Delete every administrator you did not create, every cron event you cannot explain, and every plugin you cannot vouch for, then reinstall the plugins you keep from a fresh copy. Redirect malware is almost never a single file; the visible redirect is the payload, and something else on the server keeps rewriting it.

wp user list --role=administrator --fields=ID,user_login,user_email,user_registered
wp user delete 47 --reassign=1
wp cron event list
wp cron event delete suspicious_hook_name

DollyWay is the clearest example. GoDaddy’s researchers found that its current version reobfuscates itself and reinfects every active plugin plus any WPCode snippets on every page load, drops a fake Hello Dolly plugin at wp-content/plugins/hello/hello.php, stashes settings in encoded options, and creates its own admin users. Clean one plugin while the others stay active and the malware hands itself a fresh copy on the next request.


For that class of infection I deactivate every plugin, then reinstall each one I intend to keep with wp plugin install plugin-slug --force, which overwrites the directory with a clean wordpress.org copy. Premium plugins get deleted and re-uploaded from the vendor. Only then do I reactivate, one at a time, retesting the redirect after each.

Why does a WordPress redirect hack keep coming back?

Reinfection means you removed the payload but not the entry point, the backdoor, or both. Most do-it-yourself cleanups skip this part, which is why the same site gets flagged by Google Safe Browsing three weeks after it was declared clean.

Reinfection route How to spot it What closes it
Unpatched plugin vulnerability Plugin last updated months ago, or a known CVE for your installed version Update or delete; check Patchstack or WPScan for your exact version
Leftover backdoor A stray .php file in uploads or mu-plugins, or a plugin file that fails verify-checksums Delete it and reinstall the parent plugin from source
Stale backup restored Redirect returns the same day you restore Restore only from a pre-infection date, then patch before going live
Unrotated credentials New admin appears with a login from an unfamiliar IP Rotate all passwords, salts, and API keys; enforce two-factor

The numbers behind this are not encouraging. In Patchstack’s 2025 data, 46 percent of disclosed WordPress vulnerabilities had no patch available on the day they went public, so updating alone could not have closed them. For the heavily targeted ones, mass exploitation began a median of five hours after disclosure. On the backdoor side, Sucuri found at least one backdoor on 49.21 percent of the sites it remediated in its 2023 Hacked Website report.


Put those together: the redirect got in through a plugin, and roughly half the time it left a second door open. If you never asked how it got in, assume it will be back.

Hardening That Stops the Next Redirect

Patch fast, block PHP where it does not belong, and lock the file system so the payload has nowhere to write.

  • Update plugins within days of a security release, not months. With a five-hour median exploitation window, monthly update cycles leave the door open for weeks. A pre-update snapshot means a bad update rolls back in under 60 seconds instead of becoming an excuse to delay.
  • Deny PHP execution in uploads. Apache: RewriteRule ^wp-content/uploads/.*\.php$ - [F,L] in the root .htaccess. Nginx: a location ~* /uploads/.*\.php$ { deny all; } block.
  • Disable the dashboard file editor, and file modifications where practical. define('DISALLOW_FILE_EDIT', true); at minimum. Sites that never install plugins from the dashboard can add DISALLOW_FILE_MODS so an attacker with an admin session still cannot upload a fake plugin.
  • Run a firewall with file integrity monitoring. Wordfence’s scanner compares core, plugin, and theme files against known-good copies and flags new files in uploads, covering most of the file-based hiding places listed earlier.
  • Turn on two-factor for every administrator and audit the user list monthly. A quiet extra admin is the single most common thing I find on repeat-infection sites.

After the site is clean, request a review in Google Search Console under Security Issues so the browser warning lifts. Retest from a phone with a search referrer first; if Google can still trigger the redirect, the review fails and the clock resets.

Two Commands to Run Today

Run wp option get siteurl and wp plugin verify-checksums --all on your site now, before you have a problem. Both take seconds and together cover the fastest-to-fix and most common carriers of a WordPress redirect hack. If either returns something unexpected, you caught it early, while it is one option and one plugin rather than every plugin and a cron job that rewrites them.

If the results come back messy, or the redirect has already returned once, the job has shifted from cleanup to investigation, and that is what our WordPress malware removal service is built for: tracing the entry point and every file the attacker touched so the second cleanup is the last one.

Frequently Asked Questions

Redirect keeps coming back after every cleanup?

We trace the redirect to every file, database row, and backdoor it touched, close the entry point, and monitor for reinfection with Wordfence.