261 cPanel accounts
One WHM server hosting a Scotland-based client’s WordPress sites and several large WooCommerce shops under one hosting boundary.
Incident report · Hidden ELF backdoor
A Scotland-based client called after one of their WooCommerce shops was listed as malicious on VirusTotal. Wordfence reported 283 infected files. ImunifyAV agreed at the file level. The database export was completely clean — no injected rows, no hidden administrator, no obfuscated code. All three results were accurate, and none of them found the backdoor: a packed x86-64 ELF binary sitting outside the web root entirely, in a hidden configuration folder inside the hosting account’s home directory.
Published Last reviewed
Start here · plain English
The client operates a single WHM server carrying 261 cPanel accounts — WordPress sites plus several high-volume WooCommerce shops. The engagement began when one of those shops started appearing as malicious in VirusTotal results, which is a revenue problem long before it is a technical one.
The first round of evidence looked conclusive. Wordfence reported 283 infected files on the affected site, spread across several plugin files and the active theme. ImunifyAV, running on the cPanel side, produced a comparable file-level picture. A full SQL export of the site database was searched for injected markup, encoded values, unknown administrators, and modified options — and came back clean.
That combination is the finding. A pure file-modification infection, with no database persistence, no rogue administrator, and no obfuscated PHP loader, means the attacker never needed WordPress-level persistence — because something outside WordPress already had permission to rewrite those files whenever it wanted.
It did. A 1,388,544-byte packed x86-64 ELF executable was staged in the cPanel account’s home directory at ~/.config/htop/defunct — outside public_html, in a hidden folder that belongs to a legitimate Linux process viewer. No WordPress scanner reads that path, and no database export contains it.
One WHM server hosting a Scotland-based client’s WordPress sites and several large WooCommerce shops under one hosting boundary.
Wordfence correctly flagged injected plugin and theme files on the shop whose listing triggered the call.
The full SQL export contained no injected content, no hidden administrator, and no obfuscated code — and that was the clue, not the reassurance.
Found only by reviewing the filesystem with root SSH access: ~/.config/htop/defunct, owner-only mode 0700, created 23 August 2026.
How the incident surfaced
Nobody on the estate received a security alert first. The shop owner discovered the problem the way most owners do: a public reputation service flagged the domain, and the consequences — browser warnings, ad-platform rejections, nervous customers — arrived immediately.
The natural request at that point is “clean the 283 files so the listing clears.” On a single-site install that is sometimes the whole job. On a WHM server with 261 accounts, an infection that rewrote files inside several plugins and the active theme raises a different question, and it is the only question worth answering first: not which files were changed, but what had the ability to change them.
A WooCommerce store on the estate began showing as malicious in VirusTotal results — a reputational and revenue event that set the response clock, not a technical alert.
283 files flagged on the affected site across several plugins and the active theme: widespread modification of legitimate files, not one isolated dropper.
The cPanel-side scanner returned a comparable file-level picture. Nothing in what the client saw pointed above the document root.
A complete SQL export was searched for injected markup, base64 blobs, unknown administrators, unexpected autoloaded options, and scheduled events. It was clean.
With a shared WHM boundary, several revenue-critical stores, and a file-write capability nobody could account for, the engagement moved from site cleanup to server incident response.
Three clean results, one compromise
A clean database export is usually reported as good news. In this case it was the strongest indicator that the investigation was not finished. Most commodity WordPress infections leave something behind in the database, because that is how they survive a file cleanup: an injected script in the options table, an extra administrator, a scheduled event that rewrites the dropper. None of that was present.
The absence of an obfuscated PHP loader pointed the same way. Injected PHP is how an attacker regains file-write access through the web application. If files are being rewritten and no such loader exists, the write capability is arriving from somewhere else — a compromised system account, stolen SSH or SFTP credentials, or a process running as the account user.
So the correct reading of “Wordfence: 283 files, ImunifyAV: same, database: clean” was never “almost clean.” It was “we have found the damage and none of the mechanism.”
| Evidence source | What it reported | What that actually proves | What it cannot prove |
|---|---|---|---|
| Wordfence scan | 283 modified or injected files across plugins and the active theme. | Application files were rewritten after they were installed. | Which process wrote them, or whether that process still has access. |
| ImunifyAV (cPanel) | File-level detections consistent with Wordfence; nothing server-level surfaced to the client. | The infected files matched known malicious patterns. | That the account home directory above the document root is clean. |
| SQL database export | No injected rows, no unknown administrator, no encoded option values, no rogue scheduled events. | The attacker did not need WordPress-level persistence. | That no persistence exists elsewhere in the account or on the server. |
| Lockora Security Audit | WordPress core integrity, hardening state, component exposure, and user and capability review. | Which application-level controls were missing, drifting, or already sound. | Anything above the WordPress installation directory. |
| Filesystem review over root SSH | One hidden, recently created, non-standard ELF binary in the account home directory. | An executable backdoor artifact was staged inside the hosting account. | When it last ran, or what it did while it was running. |
How the backdoor was found
Lockora Security Audit was used to get a fast, consistent posture and integrity picture across the WordPress installations — core file integrity, hardening state, component exposure, and a full user and capability review. Lockora is our own plugin, published in the WordPress.org directory; it is used in engagements like this one because it produces the same structured output on every site in an estate, which makes the outliers obvious.
What that audit produced was not the backdoor. It produced the elimination. Once core integrity, configuration, users, roles, and the database were all accounted for, the remaining explanation for repeatedly rewritten plugin and theme files was no longer inside WordPress. It was underneath it.
The rest of the work was a filesystem review from root SSH on the WHM server: enumerate what exists, bound the search by the time window the infected files provide, and look specifically for things that have no business being in a hosting account.
Work from root SSH on the WHM server rather than from inside a single cPanel account, so the review is not limited by the permissions — or the visibility — of a user that may already be compromised.
Use the modification timestamps of the infected plugin and theme files to define a search window instead of scanning 261 accounts blindly. Everything written inside that window is a candidate.
Review the account home directory itself: dot-directories such as .config, .cache, .local, and .ssh, plus temporary and mail paths. These are the locations a WordPress scanner never reads and an owner never opens.
A hosting account serving WordPress has no legitimate reason to contain a user-owned, multi-megabyte compiled binary. File type, size, permission bits, and creation date are enough to isolate it — no reverse engineering required.
Capture the full path, ownership, permission mode, size, timestamps, and SHA-256 hash, and preserve a copy of the file, before any removal decision is taken. Deleting the only evidence turns the rest of the investigation into guesswork.
Submit the artifact for targeted scanning and compare its path and characteristics against published research, rather than trusting a single signature match in either direction.
The artifact
The file was not PHP, not a script, and not part of any installed application. It was a compiled Linux executable, deliberately placed in a directory that belongs to htop — a legitimate interactive process viewer whose configuration lives in ~/.config/htop on a normal system — and named to resemble a dead process entry in a listing.
The properties below are the complete set of observations retained from the review. The hash and path are published on purpose: they are indicators other administrators can check against their own servers.
| Property | Observed value |
|---|---|
| Path | ~/.config/htop/defunct — inside the cPanel account home, outside the document root |
| File type | Malformed / packed x86-64 ELF executable |
| Size | 1,388,544 bytes (approximately 1.36 MB) |
| SHA-256 | 745fc2346e9ad0fdd00104c6d8732ecf7759cb053bd61c296c7b26e9ddb98d50 |
| Permissions | 0700 — readable, writable, and executable only by the owning user |
| Ownership | The site’s own cPanel user; not root, not a system account |
| Created | 23 August 2026 |
| Targeted scan result | Imunify heuristic classification SMW-HEUR-ELF |
| Runtime state at discovery | Not running; not open by any process |
| Persistence references | No cron entry, shell profile, or startup reference found |
| Paired key file | The commonly associated defunct.dat was absent |
Assessment · high confidence
The ~/.config/htop/defunct path is highly distinctive, and it is chosen for exactly the reasons that make it effective: htop is a legitimate tool, ~/.config is a legitimate hidden configuration directory, and “defunct” reads as a dead process entry to anyone skimming a listing. Nothing about the location looks like malware until you ask why a shared hosting account contains a compiled binary at all.
That path, combined with a packed x86-64 ELF of roughly this size in a hosting account, matches the Global Socket (gsocket) deployment pattern documented in Sansec’s malware research and in independent handler reports. On that basis the artifact is assessed with high confidence as a gsocket covert backdoor component.
gsocket itself is legitimate open-source software from The Hacker’s Choice. It establishes an end-to-end encrypted TCP session between two endpoints through a public relay network, addressed by a shared secret instead of an IP address and port. For an attacker holding a hosting account, that is close to ideal: no inbound port has to be opened, NAT and firewall rules are bypassed by design, and the traffic is encrypted and outbound, so a perimeter built around inbound rules never sees it.
Two observations argue against a fully activated channel at the moment of discovery. There was no defunct.dat — the paired file that commonly holds the shared secret — and no cron entry, shell profile, or startup reference invoking the binary. The plausible readings are that the capability was staged but not yet activated, that the launcher and key file were removed by an earlier partial cleanup or by the operator, or that activation used a route not preserved in the retained evidence. The available evidence does not settle which.
The path, file characteristics, permissions, and account context match a documented gsocket deployment pattern.
Nothing in the retained evidence proved the binary ever ran on this server, and it was not running or open by any process when found.
No inbound port, NAT and firewall traversal through a public relay, end-to-end encryption, and a binary that can masquerade as an ordinary process.
gsocket deployments commonly store the shared secret beside the binary. Its absence moves the assessment from “active channel” toward “staged capability” — without proving either.
gsocket is public software used by many unrelated actors. Naming the toolkit says nothing about who deployed it here.
A staged remote-access capability inside an account on a 261-site server is treated as an active compromise until access is rotated and the estate is verified.
Why the scanners missed it
It is tempting to conclude that Wordfence and ImunifyAV underperformed. They did not. They answered the questions they are built to answer, and the backdoor sat outside those questions.
Wordfence is a WordPress plugin. It runs inside the WordPress installation, and its file scanning is oriented around WordPress core, plugins, themes, and PHP content in the document root. A compiled binary in the account home directory is not in scope, contains no PHP for pattern matching to match, and is not reachable over the web at all.
ImunifyAV runs server-side and can see the account home. When the file was scanned directly it did match — as SMW-HEUR-ELF. That classification is a broad heuristic meaning roughly “an ELF binary where one is not expected in a user home directory,” not a gsocket-specific signature. Heuristics of that class are well known for flagging legitimate binaries, which is precisely why they get triaged as noise, allowlisted wholesale, or switched off. What the retained evidence does not establish is which of those happened here — only that nothing in the client’s scan results led anyone to that file.
MITRE ATT&CK mapping
The mapping below describes behavior in shared vocabulary. It does not identify a threat actor, and it separates what was observed on disk from what the tool class is capable of. Where a mapping rests on the assessed identification rather than on observed execution, that is stated in the confidence line.
The binary was stored in ~/.config/htop — the configuration directory of a legitimate process viewer — under a filename that reads as a dead process entry.
Placement inside a dot-directory kept the artifact out of ordinary file listings, FTP clients, and control-panel file managers used by the site owner.
The executable was a malformed and packed x86-64 ELF, which frustrates static inspection and signature matching against the unpacked tool.
gsocket provides interactive remote shell access using legitimate, publicly available software. The capability was staged on the account; execution on this server was not established.
gsocket reaches its operator through a public relay network rather than a direct inbound connection, which is what makes it effective behind NAT and inbound firewall rules. No relay traffic was recovered from this environment.
Scope and limitations
| Area | Evidence considered | Boundary |
|---|---|---|
| The artifact | Path, ownership, permissions, size, timestamps, SHA-256, targeted scan classification, and runtime state at discovery. | The binary was not reverse-engineered. The identification rests on characteristics, location, and published research. |
| Execution history | Process table, open file handles, cron entries, shell profiles, and startup locations at review time. | The absence of a reference at review time does not prove the binary never ran earlier. |
| Initial access | File timestamps, account layout, shared-service exposure, and the logs still available. | No entry vector is claimed. Log retention on shared hosting is rarely sufficient to prove one after the fact. |
| Blast radius | 261 cPanel accounts on one WHM instance, several of them revenue-critical WooCommerce stores. | Accounts not individually reviewed are not certified clean by this report. |
| Visitor and customer impact | Website-side file modifications and the public reputation listing that followed. | Customer data access, order manipulation, and payment exposure require their own evidence and were not established here. |
| Client identity | Region and estate size are described so the scale of the environment is understood. | Client name, domains, cPanel usernames, IP addresses, log excerpts, and credentials are redacted. |
Check your own server · IOC triage
Every check below is read-only. Run them from a trusted device with root access, and preserve what you find — path, owner, permission mode, size, timestamps, and hash, plus a copy of the file — before deleting anything. A deleted artifact cannot be classified, and an unclassified artifact leaves you guessing about how far the compromise reached.
A match is not automatically this backdoor. Legitimate binaries do live in home directories on some systems, and heuristic ELF detections produce false positives. The point of the table is to tell you which observations deserve an explanation, not to declare every one of them malicious.
| Check | Where to look | What raises concern | First safe action |
|---|---|---|---|
| The documented gsocket paths | ~/.config/htop/defunct and ~/.config/htop/defunct.dat in every account home, plus similar decoy locations under .ssh, .cache, and .local. | Either file present. The .dat file holds the shared secret that lets whoever has it open a session to your server. | Treat it as an active compromise: preserve the evidence, isolate the account, and start credential rotation immediately. |
| Known file hash | File hashes across all account home directories. | A file matching SHA-256 745fc2346e9ad0fdd00104c6d8732ecf7759cb053bd61c296c7b26e9ddb98d50. | Preserve the file, then treat that hosting account and every credential it holds as compromised. |
| Executables where none belong | Every /home account home, including hidden dot-directories, temporary paths, and mail directories. | A user-owned executable file — commonly mode 0700 — in an account that should hold only web content, mail, and configuration. | Record path, owner, mode, size, timestamps, and SHA-256; keep a preserved copy before any removal decision. |
| Processes with implausible names | The running process list, including entries styled as kernel threads in square brackets. | A process presenting as a kernel thread but owned by a hosting user, or a running process whose executable path has been deleted. | Capture the process, its owner, its open file handles, and its network connections before terminating anything. |
| Unexplained outbound sessions | Long-lived outbound TCP connections originating from hosting user accounts. | Persistent outbound sessions from a web hosting account to hosts unrelated to updates, mail, payments, or your CDN. | Record endpoints and timing. Do not assume inbound firewall rules would have prevented the channel — they do not apply to it. |
| Account-level persistence | The crontab of every hosting user, plus ~/.bashrc, ~/.bash_profile, ~/.profile, and any user service units. | Entries invoking a binary from a dot-directory, or lines appended long after the account was created. | Preserve the file, then compare it against a known-good account of similar age on the same server. |
| File-write correlation | Modification timestamps of the infected plugin, theme, and core files. | Application files rewritten in a tight window with no matching deployment, update, or editor session to explain it. | Use that window to bound the rest of the search across the account and the server, rather than scanning everything at once. |
| Cross-account repetition | The other accounts on the same WHM server, especially those sharing an owner, a deployment routine, or a backup source. | The same artifact, path, timestamp cluster, or infection pattern appearing in more than one account. | Escalate to a server-level incident. Do not certify individual accounts clean while a shared cause is unexplained. |
Containment and eradication
Copy the artifact, hashes, timestamps, and logs before anything is deleted.
Isolate the affected account and close the access the binary would have used.
Change every credential the account and the server hold, from a trusted device.
Replace the infected application files from verified sources instead of editing them.
Re-check the estate after caches, cron, updates, and normal traffic have run again.
Keep the binary, its hash, its timestamps, its ownership, and the surrounding directory listing. This is the only material that can later answer how far the compromise reached.
Restrict or suspend the account rather than the whole server where the business allows it, and remove the account user’s ability to execute binaries from its home directory.
Everything that user could reach is in scope: its document roots, its cron, its SSH keys, its mail, its databases. Everything it wrote since the artifact’s creation date is untrusted until it is verified.
WHM and cPanel logins, SSH keys, FTP and SFTP accounts, database users, WordPress administrators and application passwords, API tokens, payment and shipping integrations, and deployment secrets — rotated from a device that is not part of the incident.
Replace WordPress core, plugins, and themes from verified sources rather than stripping injected lines. 283 flagged files is a rebuild, not an edit — and hand-editing leaves the ones nobody flagged.
A backdoor in one account on a 261-account server is a server-level finding until the same method has been applied to the others. Shared owners, shared deployment routines, and shared backups are the priority order.
Establish how the account user could write to plugin and theme files at all, how a binary could be dropped and executed from a home directory, and whether account isolation on the server actually holds under test.
Verify after caches expire, cron runs, plugin updates apply, and traffic returns. That is the point at which an incomplete cleanup reveals itself — not the moment the homepage looks right.
Prevention for hosts and agencies
Alert on new executable files anywhere in account home directories — not only inside document roots, which is where every application scanner already looks.
Where the hosting model permits it, prevent execution of user-written binaries from home, temporary, and upload paths. A backdoor that cannot execute is an artifact, not a channel.
A relay-based backdoor needs no inbound port, so inbound firewall rules never see it. Baseline what hosting accounts normally connect to and alert on the rest.
Separate system users, restricted shells, controlled cron, and least-privilege database users limit how far one compromised site can reach on a 261-account server.
It is noisy, and the right answer is an allowlist of known-good binaries with a triage routine — not disabling the only class of detection that would have flagged this file.
An application scanner, a server scanner, and a filesystem review answer three different questions. A clean result from one is never a clean result for the server.
Conclusion
Wordfence found 283 infected files and was right. ImunifyAV agreed at the file level and was right. The database export was clean and that was true. A cleanup built on those three results would have removed the visible damage, restored the shop, and cleared the public listing — while leaving a remote-access capability inside a hosting account that had write permission over every file it had just rewritten.
The finding came from one deliberately unglamorous step: looking outside the application, with root access, at the directories a site owner never opens. That step is the difference between a site cleanup and a server incident response, and on an estate of 261 accounts sharing one boundary it is not optional.
Client identifiers, domains, account names, and log excerpts are withheld from this report. The file hash and the path are published on purpose — they cost an attacker nothing and they let another administrator check their own server tonight.
Common questions
Not in the ordinary case. Wordfence runs inside the WordPress installation and is oriented toward WordPress core, plugins, themes, and PHP content in the document root. The binary sat in the hosting account’s home directory above that root, contained no PHP, and was never reachable over the web. It found the damage correctly — the mechanism was outside its scope.
It is useful evidence, and it is often misread. Most commodity WordPress infections leave database persistence behind. When files are being rewritten and the database is clean, with no rogue administrator and no obfuscated loader, the likely explanation is that the attacker has write access from outside the application — which is a more serious situation, not a less serious one.
Not as a first move. Preserve a copy along with its path, owner, permission mode, size, timestamps, and SHA-256 hash first. Deleting the artifact destroys the only material that can establish whether it ran, what it could reach, and whether another copy exists in a different account — and the account credentials still need rotating either way.
No. It means the shared secret was not sitting next to the binary at the time of review. The capability may have been staged and not yet activated, or the launcher and key file may have been removed earlier. On a server carrying 261 accounts, a staged remote-access binary is handled as an active compromise until access has been rotated and the estate verified.
No. gsocket is legitimate open-source networking software from The Hacker’s Choice, used lawfully for remote administration through NAT and firewalls. What makes this instance malicious is the context: an unexplained, packed, owner-only copy hidden in the configuration directory of a hosting account that has no legitimate use for it, on a site whose plugin and theme files were being rewritten by something nobody could account for.
Start with a read-only sweep of every account home for the paths and hash in this report, then bound a wider search by the timestamps of any files you already know were modified. If anything turns up in more than one account, treat it as a server-level incident rather than a set of site cleanups — that distinction determines whether the cleanup holds.
Choose the response path
One infected WordPress or WooCommerce site
Best for an owner whose site is flagged, blocklisted, or reinfecting after a cleanup that removed everything the scanner reported.
A WHM server, host, or agency estate
Best when many cPanel accounts share one server, one owner, or one deployment routine — and a finding in one account has to be answered for all of them.