Cloaker Malware Stopped in 48 Hours, 22K Visits Saved

Four months after taking a medical tourism clinic from 7,600 to 22,000 organic visits a month, someone tried to delete all of it. A cloaker was serving Indonesian gambling pages to Google’s crawler while showing the clean site to every human visitor. It had been doing it for weeks.

The outcome if we had not caught it is not speculative: Safe Browsing flag, then a hacked-content manual action, then de-indexing, then 22,000 visits a month to zero, and for a healthcare client the loss of commercial credibility on top of the traffic.

It did not happen. 48 hours from identification to confirmed clean, seven consecutive verification checks over 32 hours, zero rankings lost, zero Search Console warnings, zero Safe Browsing flags. This is the protocol, written to be repeated rather than admired, plus the part almost nobody in SEO knows about: the cloaker was not the vulnerability. It was the second stage.

Client: anonymised, a medical tourism clinic in a YMYL sector · Target market: Italy plus cross-border international · Incident window: second half of 2026 · Attack type: GRESIKTOTO cloaker malware plus dormant DNS TXT hijacking of Search Console ownership · Traffic at risk: 22,000 organic visits a month · Time to clean: 48 hours · Consultant: Jeansy Sese

Executive summary

Entry vector: hosting credentials compromised months earlier, before two-factor authentication was enabled, combined with a pre-authentication vulnerability in a mainstream WordPress plugin.

Potential impact: Google Safe Browsing flag, a hacked-content manual action, total de-indexing, loss of the featured snippets the site had won.

Actual impact: zero. Clean-up completed in 48 hours, seven consecutive Googlebot checks clean across 32 hours of monitoring, no ranking movement, no Search Console warning, no traffic lost.

The part worth your time is not the malware. It is the dormant vector: a google-site-verification TXT record planted in the DNS zone months in advance, which silently granted the attacker Search Console ownership the moment a subdomain went live. No file integrity monitor, no plugin scanner and no WAF would have found it, because it was never on the filesystem.

How we found it

SEO is also the discipline of reading weak signals, the patterns that will never show up in a rank tracker but that an attentive operator notices within hours. Four of them, in order of appearance:

The decisive test was trivial, and it should be monthly routine in any serious SEO audit:

curl -A "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)" \
  -s https://[client].tld/it/ | grep -iE "gresiktoto|slot gacor|situs slot|jalur link"

47 matches on a single request. The same URL opened in a browser: zero matches, a perfectly clean site.

Anatomy of the GRESIKTOTO cloaker

GRESIKTOTO is the name given to a family of Indonesian cloakers that specialise in diverting SEO traffic into illegal gambling networks. The business model is surgical:

It is the perfect parasite: it lives on the client’s SEO without killing it immediately. Google penalises cloaking when it detects it, which can take weeks. Meanwhile the attacker earns.

Why medical tourism sites are chosen

High-authority YMYL sites are preferred targets for three reasons. Pre-accumulated trust, because the domain already has solid credibility signals, so gambling doorways index faster. International traffic, because a multi-country target means multi-language doorways without building authority from scratch. And non-technical owners, because clinics, medical practices and health tourism agencies rarely have a security engineer in house. This client had all three.

The mechanism

The payload was a modified index.php in two strategic directories, /it/ and /en/, precisely the folders carrying the most SEO weight. In pseudo-code:

<?php
if (stripos($_SERVER['HTTP_USER_AGENT'], 'googlebot') !== false
    || stripos($_SERVER['HTTP_USER_AGENT'], 'bingbot') !== false) {
    // Serve gambling payload with spam title, H1 and body
    include 'wp2.php';   // static payload, deliberately never touches the DB
    exit;
}
// Otherwise: continue the normal WordPress bootstrap
require __DIR__ . '/wp-blog-header.php';

Two non-obvious details deserve attention, because they are why the usual defences missed it.

The payload was static, not dynamic. The file wp2.php, named to sit comfortably among legitimate WordPress files, served pre-generated HTML without ever querying the database. No suspicious MySQL queries, no anomalous database access pattern. Database-oriented intrusion detection does not see this at all.

It was a fork of the bootstrap, not a replacement. The index.php was not wholly malicious. It ran the payload only on a user-agent match and otherwise let WordPress run normally. That makes detection by diff harder and, more importantly, means the file works for anyone testing it from a browser in an admin session.

The SEO impact that was avoided

RiskEstimated probabilityImpact
Google Safe Browsing flag70% within 30 daysMinus 100% organic traffic within 24 hours
Manual action, hacked user-content40% within 45 daysSelective de-indexing of infected URLs
Manual action, pure spam15% within 60 daysDe-indexing of the entire domain
Loss of featured snippets90% within 14 daysMinus 40% click-through on target queries
Loss of topical authorityCertainThree to six months to recover after clean-up

Probabilities are my own estimates based on documented cases of this cloaker family, not measured outcomes. They are here to size the decision, not to be quoted as data.

The most common scenario in the literature is the first: a Safe Browsing flag, which makes Chrome show the red “Deceptive site ahead” interstitial to anyone opening the site. For a healthcare client that is the end of commercial credibility, not just of traffic. The worst is the third, where recovery needs a reconsideration request, a certified clean-up and generally six to twelve months to return to pre-incident levels.

The dormant vector: DNS plus Search Console hijacking

The cloaker was not the vulnerability. It was the symptom. The real vulnerability was two dormant elements, triggered in sequence.

Vector 1 — Compromised hosting credentials

The credentials for the client’s managed shared hosting account had been compromised months earlier, most likely through phishing or password reuse. The attacker sat on them without using them, which is a typical pattern: steal today, monetise later, avoid the temporal tripwires that catch an immediate login.

When the client later enabled two-factor authentication on the hosting account, the attacker did not lose access. They had already placed dormant TXT records in the domain’s DNS zone, weeks before. Those records did nothing visible. They waited.

Vector 2 — The phantom google-site-verification TXT

This is the trick most SEOs do not know. A google-site-verification TXT record on the domain root verifies ownership in Search Console not only for that domain, but for any URL-prefix property that starts with it. Subdomains included. Specific paths included.

The attacker had planted a google-site-verification=R1VT... record in the DNS months earlier. As long as the target subdomain was not live, the Search Console verification stayed pending. Silent. Invisible.

When the client launched a subdomain, a new landing page on the same infrastructure, Search Console completed the pending verification automatically. The attacker became a legitimate owner of that subdomain in Google’s eyes without touching anything at deploy time. The only trace was a notification email: new owner added.

At that point the attacker held:

The cloaker on /it/ and /en/ was the second stage. The first stage was ownership, planted months earlier and triggered at the right moment.

Why this changes the job description

Most WordPress incident response frameworks concentrate on file integrity monitoring, plugin and core vulnerability scanning, and malware detection in PHP files. None of those would have found the dormant DNS TXT records. They are not on the site’s filesystem, not in a plugin, not in a PHP file. They are in the DNS zone: a separate system, often managed from a different panel, with audit logs nobody reads.

If you do SEO on domains with commercial value, DNS TXT records belong in your monthly audit, not your client’s IT team’s, because the consequence of a malicious TXT record is an SEO consequence.

The clean-up protocol

The exact operational sequence, in priority order.

Step 1 — Isolate, do not delete

The golden rule: never delete malicious files before taking a forensic copy. You need it to understand the vector, find the other compromised files and reconstruct the timeline. Copy every suspect file out of the document root into a directory the webserver does not serve, and preserve the original timestamps with cp -p.

Step 2 — Vanilla restore, not manual cleaning

For compromised core files, do not attempt to clean them by hand. The risk of leaving a nested backdoor is too high. Replace them with a vanilla copy downloaded directly from wordpress.org, preserving wp-config.php only after verifying it. If the client has legitimate customisations in index.php, which is rare, document them first and reapply them after.

Step 3 — Hard credential rotation

In this order: hosting passwords for every account and not just the admin, SSH keys revoked and regenerated, the MySQL password with wp-config.php updated, WordPress passwords for every user at editor level or above, WordPress salt keys regenerated, API keys for every integrated service such as mailer, CRM and payments, and two-factor authentication everywhere it is available, including hosting, Search Console and the WordPress admin.

Step 4 — Full DNS audit

This is the step most protocols skip. Export the complete DNS zone and check every single TXT record, particularly google-site-verification, facebook-domain-verification, expired _acme-challenge entries, and any SPF or DKIM record with an undocumented selector.

For each google-site-verification record: identify which Google account it belongs to by asking the presumed owner directly; if nobody on the team confirms creating it, delete it immediately; then regenerate a verification you control, to keep legitimate ownership.

Step 5 — Search Console clean-up

Remove every owner or user you do not recognise, check owners on every property and sub-property, check whether the disavow file has been modified by looking at its timestamp, check the removals tool for recent requests, and confirm that the submitted sitemap is yours and not an injected one.

Step 6 — Patch the upstream vulnerability

Here the re-entry vector was a mainstream WordPress plugin with an open pre-authentication CVE: authentication bypass with remote code execution through an unvalidated file upload. Updated during the clean-up week.

The principle: cleaning without patching the entry point is bailing out a boat without plugging the hole. It fills back up.

Step 7 — Googlebot verification, the step everyone skips

Without this step, never declare a clean-up finished. Test eight to ten representative URLs, including the homepage, the language roots, deep pages and a deliberate 404, requesting each one with Googlebot’s user agent and checking four things in the response:

for url in "https://client.tld/" "https://client.tld/it/" \
           "https://client.tld/it/sub-page-1/" "https://client.tld/en/" \
           "https://client.tld/it/does-not-exist-xyz/"
do
  response=$(curl -A "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)" -s "$url")
  hits=$(echo "$response" | grep -icE "gresiktoto|slot gacor|situs slot|jalur link|gresikvip")
  title=$(echo "$response" | grep -oE '<title>[^<]+</title>' | head -1)
  canonical=$(echo "$response" | grep -ciE 'rel=["'\'']canonical["'\'']')
  size=$(echo -n "$response" | wc -c)
  echo "$url -> size=$size | hits=$hits | canonical=$canonical | $title"
done

What the output must show:

Repeat the test every four to six hours for 24 to 36 hours. A cloaker can be time-scheduled, active only in certain windows, or set to reappear automatically through cron. One clean check proves nothing.

On this client we ran seven consecutive checks from T+0 to T+32 hours. Five of nine URLs were byte-identical to the previous check, confirming the WordPress cache had reached steady state. Zero gambling hits. Correct titles and canonicals. Working 404. Only then did we call it clean.

Step 8 — Thirty days of monitoring

An automated Googlebot check every six hours through cron, an immediate alert on any gambling hit, Search Console coverage monitoring for unexpected URLs, Performance query monitoring for gambling patterns, and a weekly DNS TXT audit.

The legal dimension: YMYL, GDPR and liability

This case had a dimension classic SEO case studies do not: legal liability. The client operates in healthcare. Pure YMYL. The site collected contact requests containing health information, specific questions about treatments and optional patient photographs. Under GDPR those are special category data, Article 9.

An attack that potentially exposes health data triggers the obligation to notify the supervisory authority within 72 hours under Article 33, where there is a likely risk to the rights and freedoms of the people concerned. Here the forensic analysis concluded that the cloaker served a static payload and never read the patient database, that there was no evidence of access to the user database from the moment of compromise, no evidence of exfiltration, and that the attacker’s objective was SEO hijacking for gambling revenue rather than data theft.

That was documented in a data protection assessment and the event was classified as a near miss: contained potential risk, no mandatory notification. The point is that the assessment has to be written down and signed by the data protection officer or equivalent, not left implicit.

Who answers if data had been exfiltrated? The short version: the data controller, which is the client. External processors, hosting, agency, developers, answer only for the parts under their direct control and only within the data processing agreement they signed. With no written DPA, liability defaults entirely to the controller.

The lesson: if your SEO agency has Search Console, FTP, database or DNS access to a client processing special category data, you need a signed DPA. That is not bureaucracy. It is the difference between being involved and being named.

Why security here is SEO, not IT

DisciplineWhat it looks atWhat it does not look at
Traditional IT securityFile integrity, CVEs, WAF, backupsDNS TXT records, Search Console ownership, user-agent cloaking
Classic SEOKeywords, backlinks, content, crawl budgetMalware, shells, plugin vulnerabilities
Security-SEOThe intersection: anything that can destroy rankings through a technical vector—

A security engineer will protect you from a data breach but will not flag a malicious google-site-verification record, because it is not an IT risk. A classic SEO will optimise your Core Web Vitals but will not request index.php with Googlebot’s user agent, because it is not an SEO job. In between there is an operational gap, and it is exactly the gap this family of cloaker is built to exploit.

The monthly Security-SEO checklist

Week 1, files and infrastructure. Diff index.php, wp-load.php and wp-config.php against the official repository. Check plugins for open CVEs. Audit WordPress users at editor level or above and remove dormant ones. Confirm two-factor authentication is active on hosting, the WordPress admin and Search Console.

Week 2, DNS and domain. Dump the full DNS zone and diff it against last month. Audit every TXT record, identify its owner, delete the phantoms. Check WHOIS privacy and that the domain expires more than a year out. Check SPF, DKIM and DMARC for consistency.

Week 3, Search Console and ownership. Users and permissions on every property, authorised owners only. Verify the disavow file by timestamp and content. Check the removals tool for recent requests. Confirm the submitted sitemap is the real one.

Week 4, behaviour and crawling. Googlebot curl test on eight to ten representative URLs, checking spam patterns, titles and canonicals. Server log analysis for anomalous user-agent patterns. Search Console query review for off-topic patterns. Coverage report review for unexpected indexed URLs.

Four hours a month. The cost of not doing it is the case you have just read.

Limits and honesty about the data

Is the framework repeatable?

Yes, with three preconditions.

Conclusion: SEO without security is a sandcastle

Building SEO authority takes months. Destroying it takes days.

Organic growth is not an asset until it is a defended asset. A ranking is not yours while a cloaker, a phantom DNS TXT record or an unpatched plugin can take it from you in 48 hours.

That is why my audits now include a dedicated Security-SEO block. Not as an optional extra. As a prerequisite.

And the detail I would keep from the whole incident is the smallest one: the attacker never needed to break in again. They had written one line into a DNS zone months earlier and waited for the client to deploy something. The defence was not a firewall. It was reading a TXT record.


Want to know whether your site is exposed to a cloaker? A Googlebot scan across ten URLs, a DNS TXT dump with phantom verification records identified, a Search Console owner check, a plugin CVE list and a remediation report. Advanced SEO consulting.

Italian version: Caso studio Security-SEO: cloaker malware fermato in 48 ore.