What a pharma hack taught me about plugin security, lateral movement, and why your regex patterns matter more than you think.
The Call No IT Admin Wants to Receive
"The website HTML code is showing Viagra ads."
Eight words. That's all it took to start a forensic investigation that would uncover a silent infection, sophisticated attack patterns, and a security vulnerability that most WordPress administrators don't even know exists.
A client reached out after their hosting provider flagged suspicious content on their WordPress site. What seemed like a simple cleanup request turned into a full-scale digital archaeology project and revealed some uncomfortable truths about shared hosting security.
The Initial Discovery: Invisible by Design
The first scan seemed almost too clean. No malware detected. Wordfence showed green checkmarks across the board. Google Safe Browsing? Clear.
But here's the thing about SEO spam injection: it's designed to be invisible.
The attackers weren't deploying ransomware or stealing data. They were doing something far more subtle, injecting hidden links into the website's content. Links pointing to gambling sites and pharmaceutical spam, wrapped in display: none CSS to keep them invisible to human visitors.
The spam only appeared to search engine crawlers. The goal? Hijack the domain's authority to boost their own sites' rankings. Parasitic SEO at its finest.
What I found:
Contaminated database records across multiple tables
Hidden HTML widgets injected into the page builder
Backdoor user accounts with administrator privileges
Custom roles with elevated capabilities designed to persist access
And the infection had been sitting there, completely undetected by standard security scans.
The Forensics: Following the Breadcrumbs
Here's where it gets interesting.
The attack vector wasn't a brute-force login or a phishing scheme. It was a vulnerability in a legitimate, widely-used plugin:
**Advanced Access Manager (AAM)**, specifically
[CVE-2020-35935](https://www.cvedetails.com/cve/CVE-2020-35935),
a high-severity privilege escalation flaw (CVSS 7.5). The attack chain looked like this:Attacker exploits AAM vulnerability
Gains administrator access
Injects spam content directly into the database
Creates backdoor accounts for persistent access
Leaves no malicious files on the filesystem
The elegance of this approach is terrifying: no files to scan, no signatures to detect, just corrupted data hiding in plain sight.
The Shared Hosting Risk Nobody Talks About
This case raised a bigger concern that extends beyond a single site.
In shared hosting environments even with separate cPanel accounts—true isolation often doesn't exist at the filesystem level.
Consider this scenario:
Attacker compromises Site A through a plugin vulnerability
Uses PHP's file_get_contents() to read wp-config.php from neighboring sites
Extracts database credentials
Connects directly to other sites' databases
Injects spam and creates backdoors—without ever "hacking" those sites directly
The shared hosting isolation we all assume exists? It often doesn't.
Sites might not be able to access each other through WordPress, but at the server level, they could be neighbors with unlocked doors.
This is why a single compromised site on a shared VPS can become a launchpad for lateral movement across every site on that server.
The Cleanup: What Actually Works
Cleaning an SEO spam injection isn't about running a plugin and clicking "Fix All." It requires systematic database forensics:
1. Identify the attack signatures
SELECT * FROM wp_posts
WHERE post_content LIKE '%viagra%'
OR post_content LIKE '%cialis%';2. Trace the contamination
Posts table: Infected content
Postmeta table: Page builder data with injected widgets
Options table: Widget areas and transient caches
Revisions: Historical copies of infected content
3. Remove surgically
Delete infected revisions (not current content)
Clean page builder JSON data manually
Remove backdoor users and roles
Delete plugin remnants from options table
4. Verify exhaustively
-- Run this until it returns 0
SELECT COUNT(*) FROM wp_posts
WHERE post_content LIKE '%spam-indicator%';The cleanup required removing:
Dozens of infected post revisions
Backdoor administrator accounts
Custom roles with elevated privileges
Plugin configuration remnants
The False Positive That Made Me Laugh
During verification scans, the site kept flagging positive for "cialis" in the database.
Panic mode: Did I miss something?
I dug deeper. The match was coming from a biographical text about a composer's political history:
"He was associated with the left because of his long-standing ties to the Communist Party... politically, he helped establish a large coalition between conservatives, socialists and leftists."
The regex pattern %cialis% was matching "soCIALISts."
Socialism almost got quarantined because it contains a pharmaceutical substring.
There's a lesson here about the importance of context-aware pattern matching and also about the unexpected places you'll find humor in cybersecurity work.
The Uncomfortable Truth About WordPress Security
This incident exposed a fundamental problem: WordPress-level security cannot protect against server-level vulnerabilities.
You can have:
✅ Strong passwords
✅ Two-factor authentication
✅ Regular updates
✅ Security plugins
And still be vulnerable if:
❌ Sites share filesystem access
❌ PHP can read other accounts' files
❌ No open_basedir restrictions
❌ No CageFS or container isolation
True site isolation requires server-level controls, something most WordPress administrators don't have access to configure.
Recommendations: What Should You Do?
For WordPress Administrators:
Audit your plugins ruthlessly (AAM is not the only vulnerable one)
Remove plugins you're not actively using
Use unique database credentials per site
Enable 2FA for all admin accounts
Regularly scan database content, not just files
Consider static site generation for brochure sites
For Server Administrators / Hosting Providers:
Implement open_basedir restrictions
Use separate PHP-FPM pools per account
Consider CageFS or container isolation
Disable dangerous PHP functions (exec, shell_exec, system)
Enable ModSecurity with OWASP ruleset
For Decision Makers:
Understand that "managed WordPress hosting" has different security levels
Ask your hosting provider specifically about cross-account isolation
Factor in incident response costs when evaluating security investments
A modest monthly investment in proper isolation is cheaper than forensic cleanup
Final Thoughts
This case reinforced something I've learned over years of security work: the most dangerous vulnerabilities are the ones you assume don't exist.
Every WordPress administrator assumes their sites are isolated from each other. Every hosting provider assumes cPanel accounts provide adequate separation. Every security plugin assumes it can see all threats.
Assumptions are technical debt with compounding interest.
Oh, and one more thing: next time you're writing regex patterns for security scanning, remember that political ideologies might contain pharmaceutical substrings.
Socialism, it turns out, has always had a little something hidden inside it.
Have you encountered similar SEO spam injections? I'd love to hear about your forensic adventures in the comments.