The scanner is not lying to you, it is being lied to
On 29 July 2026, Joe Youngblood posted an alert that the Japanese keyword hack is moving through WordPress sites at speed and, in his words, “easily defeating WordFence, Securi, and Malcare along with other security methods / plugins.”
That last part is the interesting one, and it is not a failure of those products in the way it looks. The reason a scan comes back clean is that the payload is not there when the scanner asks for it.
The injected content is served conditionally. The site keeps a web shell, and the shell decides at request time whether to inject. If the request looks like a browser, it returns your ordinary page. If the request looks like Googlebot, it returns a page full of Japanese ecommerce keywords linking to counterfeit goods. Your security plugin fetches the page as itself, gets the ordinary version, and reports nothing.
This is why the first symptom is almost never on the site. It is in Search Console, or in a Google result for your own brand, or in a traffic collapse nobody can explain.
Prove it in one command before you touch anything
Before you start deleting files, establish what you are actually dealing with. Fetch the same URL twice from a shell:
curl -s https://example.com/some-page/ > browser.html
curl -s -A "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)" \
https://example.com/some-page/ > crawler.html
diff browser.html crawler.html
If the two differ, and the crawler version carries links or keywords the browser version does not, you have cloaking and the diagnosis is finished. No plugin scan, no guessing.
Do the same with your sitemap. A frequent companion symptom is Search Console reporting that the sitemap “appears to be an HTML page” while the sitemap loads correctly in your browser. That is the same mechanism: something intercepts the sitemap route and serves the crawler something else.
Two more places to look, both outside the site:
- Search Console, Security Issues. If Google has classified the site, the report names the pattern and holds the review request you will need later.
- Search Console, Performance, filtered to queries you do not recognise. Japanese ecommerce terms on a Polish or German site are not ambiguous.
What each tool can and cannot see
It is worth being precise about why the scanners come back clean, because “the plugin failed” leads people to buy a different plugin rather than change the method.
| Method | Sees a modified core file | Sees a shell in uploads | Sees content served only to crawlers | Sees a seed planted months earlier |
|---|---|---|---|---|
| Plugin malware scan (signature based) | usually | often | no | only if the file matches a signature |
wp core verify-checksums | yes, deterministically | no, uploads are not checksummed | no | yes, if the file is inside core |
| Grep for base64 and eval | yes, with false positives | yes | no | yes, if the payload is unobfuscated |
| Two-fetch cloaking test | no | no | yes | yes, indirectly, it proves the site is still serving |
| Search Console Security Issues | no | no | yes, after Google has classified it | no |
The pattern in that table is the whole point. Every method that inspects files answers “is there something in the filesystem”, and every method that inspects behaviour answers “is this site currently lying to crawlers”. You need both, and only one of them is offered as a product.
Catching it early, and catching a relapse
The gap between infection and discovery is where the SEO damage happens. Three signals arrive before a traffic collapse does.
Impressions for queries that make no sense for your business. Search Console, Performance, sort by impressions, look for anything in a script you do not publish in. This is usually the earliest signal available to you and it costs a minute a week.
A page that spikes out of nowhere. In the current wave, the first injected page often shows a sudden impression jump before the rest follow. A page you have not touched in a year suddenly performing is worth thirty seconds of curiosity.
The favicon in results changing. Youngblood notes that this wave carries a distinctive favicon, visible in Search Console. A favicon you did not set is a file you did not write.
Once you have cleaned, the same two-fetch test makes a serviceable relapse monitor. This runs from any machine with curl, not from the site itself, which matters because a compromised site is a poor judge of its own state:
#!/usr/bin/env bash
# cloaking-watch.sh - alerts if the crawler view diverges from the browser view
URL="https://example.com/"
UA_BOT="Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)"
a=$(curl -s --max-time 20 "$URL" | md5sum | cut -d' ' -f1)
b=$(curl -s --max-time 20 -A "$UA_BOT" "$URL" | md5sum | cut -d' ' -f1)
if [ "$a" != "$b" ]; then
echo "DIVERGENCE on $URL at $(date -u +%FT%TZ)"
exit 1
fi
Two caveats before you cron this. Pages with rotating content, A/B tests, or personalised blocks will differ legitimately, so point it at a stable page such as an evergreen post or the sitemap. And a determined shell can fingerprint more than the user agent, including the requesting IP range, so a clean result here is evidence rather than proof. It still catches the common case, and it catches it within a day rather than a quarter.
Telling it apart from the other spam variants
Three infections get called “SEO spam” and they need different first moves, so it is worth spending a minute on which one you have.
Pharma spam puts drug keywords into post titles, excerpts and content. It lives in the database, it is visible to ordinary visitors, and you find it by searching wp_posts and wp_options for the terms Google is showing. If a SELECT finds the words, you are in this case, not the Japanese one.
Casino and betting spam sits between the two. It often cloaks like the Japanese variant, but it tends to arrive with injected hreflang blocks and fabricated language versions of your pages, because the operators want several markets at once. If the crawler view shows alternate-language links you never created, look there.
The Japanese keyword hack leaves the database alone. The payload is in files, rendered at request time, and only for crawlers, which is the combination that defeats both the database search and the plugin scan.
There is also a mobile-only redirect variant that switches on the user agent the way this one does, except it checks for phones rather than for Googlebot. If your visitors report being sent to another site and your own desktop tests keep coming back clean, repeat the two-fetch test with a mobile user agent string instead of Googlebot. The mechanism is identical, only the condition changes.
Verify files deterministically, then look at dates
Youngblood’s write-up suggests searching the filesystem for base64 and asking an AI model to review the list. That works, but it is the second step, not the first, because it asks a model to guess which files belong to WordPress. WordPress already knows:
wp core verify-checksums
wp plugin verify-checksums --all
This compares every core and plugin file against the official checksums from WordPress.org and names anything modified or added. It is deterministic, it takes seconds, and it produces a much shorter list to reason about than a base64 grep across the whole tree.
What checksums cannot verify: your theme, anything premium, wp-content/uploads, and mu-plugins. That is where the manual pass goes:
grep -rl --include="*.php" -E "base64_decode|eval\(|gzinflate|str_rot13" wp-content/ | head -50
find wp-content/uploads -name "*.php"
ls -la wp-content/mu-plugins/
A PHP file inside uploads has no legitimate reason to exist. Neither does an mu-plugins file you did not write, and that directory deserves particular attention because it loads automatically and never appears in the plugins list.
Then sort what you found by modification time. The bulk of injected files usually share one timestamp, which is the moment of the visible attack. The exception is what Youngblood calls the seed: a single file planted weeks, months or occasionally years earlier, with a timestamp that matches nothing else. If you clean everything except the seed, the infection returns, and it returns quietly.
The practical test for whether you got it: restore a clean index.php, wait two minutes, and read the file again. If it has reverted, something still running rewrote it, and you have not finished.
The order that matters
Cleanup order is where recoveries go wrong, and the sequence is not intuitive.
Copy before you clean. Take a full file copy and a database export of the compromised state first. Restoring a backup over the top destroys the only evidence of how entry happened, and if the backup itself is already infected, you have nothing left to compare against. Given a seed file can predate the visible attack by months, treat “restore last month’s backup” as an assumption, not a solution.
Clean, then rotate, then deal with search. In that order. Rotating credentials before the shell is gone just hands over the new ones.
Rotate more than passwords. This is the step almost every guide stops short of:
- Application passwords, in each user profile under Users, survive a password reset and keep full REST API access. They are per user, they are easy to create programmatically once an attacker has admin, and most people do not know the feature exists. Enumerate and delete them.
- Delegated owners in Search Console, under Settings, Users and permissions, live outside your site entirely. Nothing you do in WordPress removes them. Check ownership verification too, for stray HTML files or DNS TXT records.
- Database and FTP or SSH credentials, because if the entry was credential stuffing against
wp-admin, whatever else shared that password is also exposed.
Then search. Regenerate the sitemap, confirm with a live URL Inspection test in Search Console that Googlebot now receives the real page, and request a review in the Security Issues report. Resubmitting a sitemap does not clear a manual flag; the review request does.
Two pieces of the standard advice worth arguing with
The alert that prompted this article is a good piece of field reporting, and two of its recommendations deserve pushback.
“Immediately request to remove your full website via Search Console.” This is a heavier instrument than the situation usually needs. The Removals tool hides URLs from results for about six months; it changes nothing about the infection and nothing about how Google eventually re-evaluates the site. Removing the injected URL patterns with a prefix removal is proportionate. Removing the entire site also removes the pages that still bring in enquiries, and every one of those has to come back through a cancellation and a recrawl you do not control. Reach for the whole-site version when the injected pages genuinely outnumber the real ones, not as step one.
“Find any excuse imaginable to run a press release to drive fresh interest from Googlebot.” Recrawling is driven by things you can actually influence: accurate lastmod values in the sitemap, internal links from pages that get crawled often, and URL Inspection requests on the pages that matter. A press release is an expensive way to buy a few crawler visits.
The rest of that write-up, particularly the observation about the seed file having a unique timestamp and the warning to re-check index.php after restoring it, matches what these cleanups look like in practice.
Closing the door the attack actually used
The reported entry chain in this wave is specific: credential stuffing against wp-admin using leaked email and password lists, then installing a plugin to gain filesystem access, then uploading a single payload file. Each of those steps has a control that stops it.
Two-factor authentication on every administrator. Credential stuffing works because the password is already known. Two-factor makes a correct password insufficient, which is the entire attack.
DISALLOW_FILE_MODS. In wp-config.php:
define( 'DISALLOW_FILE_MODS', true );
This blocks plugin and theme installation from the dashboard entirely. In the reported chain, that is step two. An attacker holding a valid admin session cannot install the file manager plugin that gives them the filesystem. The trade-off is real and you should know it: automatic updates stop as well, so updates then run through WP-CLI or a deployment pipeline. On a site that is deployed from a repository, that is how it should work anyway.
No PHP execution in uploads. At the web server, not in a plugin. This devalues the most common path from “attacker uploaded a file” to “attacker runs code”.
Fewer administrators. Agency staff, a developer who helped once, a support contractor from two years ago. Every one of them is a credential that can be stuffed. Demote what does not need the role.
Watch Search Console rather than the dashboard. The dashboard is where this attack is invisible by design. A weekly look at Performance for queries you do not recognise catches it earlier than any scan will.
What to tell the client or your boss
If you are cleaning this for someone else, the hard part of the conversation is not technical, it is about time. Cleanup runs in hours and recovery runs in weeks, and those two collapse easily into one expectation: fix it tonight, traffic returns tomorrow. It will not, because Google has to revisit pages it previously classified as spam, and the queue depends on how often it crawled the site before.
The second thing worth saying plainly: you cannot honestly answer “was customer data taken” when server logs have seven-day retention and the seed file is from February. The answer is “we do not know and will not find out”, and that is information rather than evasion. On a store holding personal data, that gap matters for whether a breach notification obligation is triggered, so it belongs on the table at the start rather than a week later.
The third: the cost of this infection is rarely the cleanup. It is the traffic that did not arrive during those weeks, and that number is worth calculating together from pre-infection data instead of leaving it as a vague sense that things dipped.
If you are in the middle of one right now
The short version: prove the cloaking with the two-fetch test, verify core and plugins with checksums, hunt the seed by timestamp, copy everything before restoring anything, and remember that application passwords and delegated Search Console owners outlive the password reset you are about to do.
We run this sequence as part of a WordPress security audit, and the broader cleanup process, including database work and log review, is in our guide to cleaning a hacked WordPress site.
Last updated: 30 July 2026, after the current wave was reported.







