NewTry MagicWP now - first month free
Back to blog

WordPress Backdoor Rebuilds Itself After Cleanup: How to Find and Remove the SC Malware

A WordPress backdoor called SC rebuilds itself from files, the database, and shared memory. Here is how to find every copy and remove it in the right order.

WordPress Backdoor Rebuilds Itself After Cleanup: How to Find and Remove the SC Malware

You delete the malicious plugin, reload the site, and it is back. You clean the files again, and within seconds the same backdoor reappears. If that has happened to a WordPress site you look after, the problem is probably not that you missed a file. It may be that the malware was never stored in only one place.

On September 30, 2026, Sucuri published research on a WordPress infection it calls SC, and The Hacker News covered it the next day. The backdoor keeps at least eight copies of itself in files, the database, and server memory, and each copy can rewrite all the others. This article explains how that works, how to check a site for it, and the order of operations that actually removes a WordPress backdoor that keeps rebuilding itself.

TL;DR

  • SC is a post-compromise toolkit, not a plugin bug. Sucuri has not said how the attackers get in, so there is no single patch that stops it.
  • Deleting files one at a time fails by design. A drop-in, the theme, the database, or a shared-memory segment will rewrite whatever you removed on the next request.
  • Cleanup order matters: stop the early-loading trigger first, clear the copies outside the file system, then remove the files in one pass, then rescan.
  • The malware hides itself and a hidden administrator from wp-admin, so check with the shell and direct SQL, not just the dashboard.
  • Treat every password, key, and salt on the site as exposed, and find the original way in before you call it finished.

What is the SC malware?

SC is the name Sucuri gave to a family of WordPress malware, taken from the "SC_" markers it leaves in injected code. Sucuri describes it as a self-healing mesh: a set of loaders, drop-ins, a fake plugin, and a payload that all know how to restore each other. Its command channel runs over public Ethereum infrastructure rather than one fixed server.

Two things are worth being clear about. First, this is not a vulnerability with a CVE number. It is what an attacker leaves behind after getting access. Second, nobody has published how the attackers reached these sites. The Hacker News notes that the usual routes apply: known flaws in WordPress core, plugins, or themes, weak logins, supply chain attacks on popular plugins, and upload features that let someone push a PHP web shell onto the server. Until you know which one applied to your site, cleaning the infection is only half the job.

Why does the backdoor keep coming back after you delete it?

The short version is that the malware is built as a circle. Every piece can recreate the others, so removing one piece at a time just triggers a rewrite from whichever piece is left.

Here are the eight components Sucuri recovered. File names marked as variable change from site to site.

# Location Role
1 .user.ini Tells PHP to run a file before every request in that folder tree
2 wp-content/<name>.php (name varies) A visible shim that includes the hidden file next to it if it exists
3 wp-content/.<name>.php (name varies) Hidden first-stage loader that rebuilds the fake plugin
4 wp-content/db.php Early-loading drop-in that carries the full payload and rewrites the plugin when it goes missing
5 wp-content/advanced-cache.php Earliest loader when caching is on; rebuilds the plugin from five sources
6 Active theme's functions.php An injected block that does the same job as db.php
7 wp-content/mu-plugins/ (name varies) The actual backdoor, as a must-use plugin
8 wp-content/plugins/ (name varies) An identical second copy as a normal plugin

In Sucuri's sample, the fake plugin was called hyper-engine-kit, and the theme with the injected block was named khorshidi. Treat those as examples. The theme in your case is whatever theme is active, and the plugin name may differ.

A few details explain why this is so hard to clean by hand.

The .user.ini line points at a visible shim that does almost nothing on its own. Its only job is to include a hidden dot-prefixed file if one exists. If you delete the hidden file but leave the shim, the site keeps working and nothing looks broken, while another component quietly recreates the hidden file.

The advanced-cache.php drop-in is the most dangerous position. WordPress loads it before ordinary plugins whenever page caching is switched on. Instead of carrying the payload itself, it acts as a finder. It looks for a copy in an existing mu-plugin, an existing plugin folder, a shared-memory segment, a ZIP bundle, and finally the database, using the site's own database credentials to read the payload straight out of a row in the options table.

The obfuscation is also deliberate. Sucuri says none of the files contain readable function names. Each one carries a table of scrambled strings and a small decoder that turns numbers into function names, so a quick scan for suspicious function calls turns up nothing.

Where does SC hide outside the file system?

This is the part most cleanups miss. Sucuri found live copies of the payload in three places that are not ordinary files.

The database. The full payload sits in a row of the options table under a random name, compressed and encoded. A perfect file cleanup still fails, because the next page load restores everything from that row.

Shared memory. On servers that support System V shared memory, the payload can be written to a memory segment with a fixed numeric key. That segment lives in RAM, so deleting files and cleaning the database does not touch it. Sucuri also notes that on shared hosting the segment can belong to a different account, which means you may not be able to remove it yourself.

Scheduled tasks. The infection registers cron hooks, some with random names and one with a known fetch name, and a system cron job triggers redeployment on a schedule rather than waiting for visitors.

Sucuri also saw database triggers in related SC variants. A trigger runs inside the database and can recreate an administrator account whenever a row is inserted. That survives a full file restore and even the deletion of the account it keeps recreating, so cleaning up users is pointless until the trigger is gone.

What can the SC backdoor do once it is running?

The rebuild loop exists to protect the payload, and the payload gives the operator real control over the site. Based on Sucuri's analysis, it does the following.

  • Hides itself. It removes its own entry from the plugin list, the update checks, and the network plugin views, and adds admin JavaScript as a fallback to scrub itself from the plugin table.
  • Talks to a command server over Ethereum. It carries a list of roughly twenty public Ethereum RPC gateways and reads instructions from a smart contract through them. Because these are legitimate third-party services being used as transport, blocking only the one you saw in traffic leaves the rest available as fallbacks.
  • Fingerprints the site. It collects the site URL and host, WordPress and plugin versions, active themes, the mu-plugin list, and current administrator session tokens, then sends them out encrypted.
  • Takes orders. The reply can contain JavaScript to inject on the front end, which on a store enables checkout skimming, new PHP to install, and a list of security plugins to deactivate and delete.
  • Creates a hidden administrator. It adopts or creates an admin account, writes it straight into the users tables when needed, hides it from user lists and counts, and forges valid login cookies for it so the operator never needs a password.
  • Answers a beacon request. A magic request parameter is handled before WordPress finishes loading and returns a normal-looking page while the malware is present.

The practical consequences are simple. Anything an administrator could do on the site, the attacker can do. Session tokens may have been copied. If the site takes payments, visitors' card details may have been exposed through injected JavaScript. Plan the cleanup around that, not just around removing files.

How do you check whether a site has the SC backdoor?

Do not rely on wp-admin. The malware filters the plugin list, the user list, user counts, and role views, so a clean-looking dashboard proves very little. WP-CLI has the same weakness for anything that loads WordPress, because the mu-plugins and drop-ins load with it. Look at the disk and query the database directly.

Before you change anything, take a copy for evidence and for a possible restore. Store it outside the web root.

terminal
cd <site-root>
mkdir -p ~/sc-evidence
wp db export ~/sc-evidence/before-cleanup.sql
tar czf ~/sc-evidence/wp-content-before.tgz --exclude='wp-content/uploads' wp-content

Check the files

terminal
# Drop-ins, must-use plugins and plugins, read from disk
ls -la wp-content/db.php wp-content/advanced-cache.php
ls -la wp-content/mu-plugins/ wp-content/plugins/

# Hidden dot-prefixed PHP files in wp-content
find wp-content -type f -name '.*.php'

# Directives that run a file before every PHP request
grep -rIn "auto_prepend_file" --include=.user.ini --include=php.ini --include=.htaccess .

# The SC_ marker Sucuri names as the malware's tag
grep -rIl "SC_" wp-content --include='*.php'

# ZIP files with random hex names (the length is a guess; adjust it)
find wp-content -type f -regextype posix-extended -regex '.*/[0-9a-f]{6,}\.zip'

# PHP files inside uploads, which normally should not exist
find wp-content/uploads -type f -name '*.php'

Two cautions. First, db.php and advanced-cache.php are not automatically bad. Database tools such as HyperDB or Query Monitor can use db.php, and caching plugins create advanced-cache.php on purpose. What matters is whether the file belongs to a tool you installed and whether its contents match what that tool writes. An unexpected block opening with an SC_-style marker is the red flag Sucuri describes. Second, the SC_ search will produce some false positives, so read the matches instead of deleting them in bulk.

Also compare the active theme's functions.php with a clean copy of the theme. Sucuri says the attacker appended a block at the bottom, fenced by begin and end markers, to an otherwise normal file.

Check the database

Replace wp_ with your table prefix. Read it from wp-config.php with grep table_prefix wp-config.php rather than asking WordPress, since the point is to avoid running the infected code.

terminal
# Administrators, read straight from the database
wp db query "SELECT u.ID, u.user_login, u.user_email, u.user_registered FROM wp_users u JOIN wp_usermeta m ON m.user_id = u.ID WHERE m.meta_key = 'wp_capabilities' AND m.meta_value LIKE '%administrator%';"

# Largest rows in the options table; a stored payload stands out by size
wp db query "SELECT option_name, LENGTH(option_value) AS bytes FROM wp_options ORDER BY bytes DESC LIMIT 15;"

# Options and transients with an sc_ style name
wp db query "SELECT option_name, LENGTH(option_value) AS bytes FROM wp_options WHERE option_name LIKE '%sc!_%' ESCAPE '!';"

# Database triggers
wp db query "SELECT TRIGGER_NAME, EVENT_OBJECT_TABLE, ACTION_TIMING, EVENT_MANIPULATION FROM information_schema.TRIGGERS WHERE TRIGGER_SCHEMA = DATABASE();"

Any administrator you do not recognize needs an explanation. A large option row is a lead, not proof, because page builders and caches also store big values. Core WordPress does not create database triggers, so a trigger on your WordPress tables is worth tracing to its source.

Check scheduled tasks, shared memory, and outbound traffic

terminal
# Scheduled events; look for random-looking hook names
wp cron event list --fields=hook,next_run_relative

# System V shared-memory segments on the server
ipcs -m

wp cron event list does load WordPress, so treat its output with some suspicion. For shared memory, Sucuri did not publish the fixed key in its write-up, so you cannot match a segment by number. Segments also have legitimate users, so do not remove one you cannot explain. On shared hosting you may see nothing, or not be allowed to see another account's segments, which is a question for your host.

For network traffic, look in your firewall or egress logs for requests from the web server to public Ethereum RPC gateways. A normal WordPress site has no reason to make them, unless you run a plugin built for blockchain features.

How do you remove SC in the right order?

Sucuri's central point is that order matters more than thoroughness. Remove the files first and you only trigger a rewrite. The sequence that works is to cut off execution, clear the copies that are not files, then remove the files in a single pass.

Important: Take a full backup and the evidence copy above before you start. Do the work on a staging copy first if you can, and put the live site in maintenance mode while you clean.

1. Neutralize the early trigger without deleting its target

PHP caches the auto_prepend_file value, and Sucuri says that cache can last up to 300 seconds. PHP's own documentation lists user_ini.cache_ttl with a default of 300 seconds. If you delete the target file while the cache is warm, every PHP request on the account fails until it expires.

So first replace the prepend target with an empty file, then remove the directive from .user.ini, php.ini, and .htaccess.

terminal
# Empties the file that the directive points at; do not delete it yet
: > <prepend-target>.php

2. Clear the copies that live outside the files

Remove the payload row and any control options and transients you found. Then deal with the shared-memory segment. Removing a segment you have confirmed belongs to the malware uses ipcrm, and a server reboot also clears System V segments, which is general Linux behavior rather than something from Sucuri's post. Sucuri adds that a leftover segment becomes harmless once the drop-ins that read it are gone, so if it belongs to another account, the host may need to clear it.

terminal
wp db query "DELETE FROM wp_options WHERE option_name = '<payload-option-name>';"

If any of these copies survive, the next request through advanced-cache.php writes the whole set back to disk.

3. Remove the cron hooks and database triggers

Delete the malicious scheduled events so that system cron cannot redeploy the malware on a timer, and drop any trigger that recreates an administrator.

terminal
wp cron event delete <hook-name>
wp db query "DROP TRIGGER IF EXISTS <trigger-name>;"

4. Remove the hidden administrator

Delete the account whose capabilities are stored under the default capabilities key, and remove any orphaned option that points to its ID. Going through SQL avoids the user-list filters.

terminal
wp db query "DELETE FROM wp_usermeta WHERE user_id = <ID>;"
wp db query "DELETE FROM wp_users WHERE ID = <ID>;"

5. Clean the files in one pass

Now remove, together, the standalone loaders and the shim, both copies of the fake plugin, any hidden ZIP restore bundle, and the injected drop-ins. For db.php and advanced-cache.php, that means deleting the malicious file. If a caching plugin legitimately uses advanced-cache.php, re-saving its settings afterward regenerates a clean one.

For the theme, trim only the fenced block from functions.php so the legitimate code stays. If the theme is a stock one from a vendor, reinstalling a clean copy also works, but it will overwrite any edits you made directly in the theme. Check the result with the core and plugin checksum commands, which only cover files that WordPress.org publishes checksums for.

terminal
wp core verify-checksums
wp plugin verify-checksums --all

6. Rescan and watch for recreated files

Run a full scan, then keep watching the paths from the table above. If anything returns, a persistence point survived or the original way in is still open. Go back to the copies outside the files rather than deleting the same file again.

Should you restore from a backup or clean in place?

A clean backup is often the fastest route, but only if you can find one that predates the infection. Sucuri did not publish an infection timeline, and you may not know when your site was first compromised. Restoring a backup that already contains the infection just restores the mesh.

A restore does replace the database row and the files, which removes two of the three off-disk locations. It does not touch a shared-memory segment, but Sucuri says that becomes harmless once the loaders that read it are gone. After any restore, still check for the hidden admin, triggers, and cron hooks, and rotate credentials.

For a store, or any site where you cannot tell what the attacker saw, consider a fresh install with only your content imported, then review what you bring across. Plugins and themes should come from clean sources, not from the old file tree.

If you host on MagicWP, the practical help is around the edges of this process: daily off-site backups with one-click restore, on-demand backups before you change anything, staging for rehearsing the cleanup, and SSH and WP-CLI for the commands above. How well any scanner detects SC specifically is something to test rather than assume, and the steps in this article are worth following whatever scanner you use.

What to do after the cleanup

Removing the malware does not remove the way it got in. Work through these before you consider the site clean.

  • Rotate every credential the attacker could have touched. That includes WordPress administrator passwords, the database password, SFTP and SSH credentials and keys, hosting panel logins, and any API keys stored in the site. wp config shuffle-salts replaces the security keys and salts in wp-config.php and logs everyone out.
  • Update everything. Sucuri notes that most compromises it handles use known flaws that already have fixes. Update core, plugins, and themes, and remove the ones you do not use, including inactive ones.
  • Audit administrators and roles. Remove accounts you cannot account for and keep the number of admins small.
  • Block PHP execution in the uploads folder. The upload path is a common way to land a web shell, and no legitimate upload needs to run as code.
  • Put a web application firewall in front of the site. Sucuri recommends one to block exploit attempts and help stop the outbound command channel.
  • Block the Ethereum gateways as a set. Do this at the server or network level, only if the site has no legitimate need for them, and remember that one blocked address leaves the others as fallbacks.
  • Check other sites on the same account or server. If the entry point was shared, they may be infected too.
  • Audit the usual hiding places regularly. That means the options table, scheduled tasks, database triggers, and user accounts.

The Hacker News article reports a second item: attackers have been trying a high-severity flaw in the wpForo Forum plugin, tracked as CVE-2026-1581, scored 7.5. It is an unauthenticated time-based SQL injection through the wpfob parameter, and it affects every version up to and including 2.4.14. The article does not say that wpForo is how SC gets onto sites, and Sucuri has not named any entry point, so do not assume a connection.

The plugin's own changelog on WordPress.org lists the fix in version 2.4.15. Previdian's telemetry shows only a small number of attempts from five IP addresses in Bulgaria, Switzerland, France, the United States, and Yemen, so the volume is low. Low volume is still a reason to patch, because a public scanner template for this flaw exists.

If you run wpForo, update it. As of this writing, WordPress.org lists version 3.2.2 as current, and the plugin shows more than 20,000 active installations. The 2.x to 3.x change is a major upgrade, and the plugin's changelog says automatic updates from 2.x to 3.x are blocked, so test it on staging after a backup. To check whether anyone has already probed your site, search your access logs.

terminal
# URL-encoded payloads are possible, so treat a clean result as a hint, not proof
grep 'wpfob=' <access-log-path> | grep -iE 'sleep|benchmark'

Frequently Asked Questions

Why does WordPress malware keep coming back after I delete it?

Because something still on the server is rewriting it. A drop-in, a theme file, a database row, a scheduled task, or a shared-memory segment can each restore the files you removed. With SC, Sucuri found the payload in at least eight places, each able to rebuild the others. If a file returns, treat that as a sign that a copy outside the file system, or the original way in, is still there.

Is the SC malware caused by a WordPress or plugin vulnerability?

SC itself is not a vulnerability. It is a toolkit installed after an attacker already has access. Sucuri and The Hacker News both say the delivery method is unknown. Common routes include outdated software, weak passwords, supply chain attacks, and insecure upload features, so check all of them on an infected site.

How can I tell if my site has the SC backdoor?

Look on disk and in the database, not in wp-admin, because the malware hides itself and a hidden administrator from the dashboard. Check db.php and advanced-cache.php for unexpected code, .user.ini for an auto_prepend_file line, the theme's functions.php for an added block, and the options table for a large random-named row. Also check for unknown administrators and database triggers.

Will restoring a backup remove it?

It can, if the backup predates the infection, because it replaces both the files and the database row. It will not clear shared memory, and a backup made after infection brings the malware back. After any restore, check for hidden administrators, triggers, and scheduled events, and rotate every credential before you reopen the site.

Can a security plugin remove SC for me?

A scanner can help you find suspicious files, but it cannot reliably clean this one in a single scan, because the order of removal matters. The payload can also be told to deactivate and delete security plugins. Use a scanner to find leads and follow the removal order above rather than relying on a one-click clean.

Does this affect WooCommerce stores?

It can. Sucuri says the payload can fetch JavaScript to inject on the front end, which on a store enables checkout skimming. If a store was infected, assume customer payment data entered during that period may have been exposed, and work out your obligations with your payment provider and, where relevant, a legal adviser.

Should I block Ethereum traffic from my server?

Only if the site has no legitimate need for it. SC uses about twenty public Ethereum RPC gateways as transport, so blocking the single address you saw leaves the others as fallbacks. If you block, block the set at the network or server level, and expect problems with any plugin that actually needs blockchain access.

Conclusion

The lesson from SC is that a WordPress infection can be a system instead of a file. The way to stop a WordPress backdoor that keeps rebuilding itself is to treat files, the database, and server memory as one problem, cut off the early triggers first, clear the hidden copies, remove the files together, and then close the way the attacker came in. Deleting the visible malware and moving on is how sites end up reinfected.

Before you do any of it, make sure you have a clean restore point and somewhere safe to rehearse the cleanup. MagicWP's daily backups and one-click restore and managed security features are built for that, and the MagicWP security docs cover what the platform handles for you.

A
Alex
MagicWP
Writing about WordPress, performance, and the infrastructure that makes sites fast.

Get the best of MagicWP in your inbox.

Monthly engineering notes, product updates, and WordPress performance tips. No spam, unsubscribe anytime.

Join 12,000+ builders. We send one email a month.