Your site is hacked. Do these seven things, in this order.
Most damage in a website compromise happens after the discovery — either the attacker keeps access because nobody changed the passwords, or the owner deletes the visible symptom (the spam page, the redirect) and the actual door stays open.
First, one question that changes everything: was the entry point this week's PHP flaw (CVE-2026-109618 / CVE-2026-109619)? If the server was unpatched and reachable after 17 October 2026, treat that as the likely door. What that means →
1. Preserve, then contain — in that order
Copy the evidence before you clean. Once you delete a file, you have lost the only description of what the attacker did.
sudo mkdir -p /root/ir-$(date +%F)
sudo cp -a /var/log /root/ir-$(date +%F)/logs 2>/dev/null
sudo tar czf /root/ir-$(date +%F)/www.tgz /var/www /home/*/public_html 2>/dev/null
sudo ps -eo pid,ppid,user,lstart,args --forest > /root/ir-$(date +%F)/ps.txt
sudo ss -tunap > /root/ir-$(date +%F)/net.txt
Then block the symptom, not the evidence: put the site in maintenance mode or pull it from the load balancer. If you have shell access and active intrusion, take the host off the network rather than shutting it down — you keep the memory, the process table and the connections.
On shared hosting you cannot do any of this. Open a security ticket and ask the host to preserve access logs; ask explicitly for the PHP version history and the date the runtime was last restarted.
2. Work out how they got in
Check these three in parallel — the answer is usually in one of them:
- Server software age. Was PHP below 8.2.35 / 8.3.36 / 8.4.27 / 8.5.12 while internet-facing? Check the date of the last worker restart.
- Access logs. Look for POSTs with huge field names, multipart requests with no file part, or
PHP_SESSION_UPLOAD_PROGRESSin the body. - Plugin and theme versions. If PHP was patched, the door is usually an outdated plugin with a known file-upload or SQL-injection bug.
# PHP errors that suggest the request never reached your code
grep -h 'Allowed memory size' /var/log/php*.log /var/log/apache2/error.log 2>/dev/null \
| grep 'in Unknown on line 0' | tail -30
3. Find the shell
Attackers leave a small file that lets them run commands, then hide it. Search by location first — a PHP file in an uploads folder is never legitimate — then by shape.
# 1. PHP where PHP should never be
find /var/www /home -type f -name '*.php' \
\( -ipath '*uploads*' -o -ipath '*cache*' -o -ipath '*images*' -o -ipath '*tmp*' \) 2>/dev/null
# 2. Files changed in the incident window
find /var/www -name '*.php' -newermt '2026-10-16' -printf '%TY-%Tm-%Td %TH:%TM %10s %p\n' | sort
# 3. Configuration hijacks (persistence with no shell file at all)
grep -REn 'auto_prepend_file|auto_append_file' /etc/php /etc/apache2 /var/www 2>/dev/null
find / -name '.user.ini' -newermt '2026-10-01' 2>/dev/null
If you run WordPress, its own checksum tool is the fastest integrity check available:
wp core verify-checksums
wp plugin verify-checksums --all
wp user list --role=administrator --fields=ID,user_login,user_email,user_registered
ls -la wp-content/mu-plugins/
A file that matches nothing above is not proof of a clean site. An attacker who only used the memory-disclosure bug steals credentials and never writes a file at all.
4. Rotate every secret the site could read
This is the step people skip, and it is the one that decides whether the attacker comes back. If they had code execution as the web user, they could read anything your application could read.
- Database passwords — and any other database user whose credentials sat in a config file on that host
- Application keys and salts: WordPress
AUTH_KEY/SALTset, LaravelAPP_KEY, JWT signing keys, session secrets - Third-party API keys: payment gateway, email/SMTP, SMS, storage buckets, CDN, analytics, AI providers
- SSH and deployment keys stored on the host; cloud access keys in
.envor~/.aws - Control panel, hosting and CMS admin passwords, plus 2FA enrolment (re-enrol; an attacker may have added their own device)
- Backup credentials — attackers go for backups because that is how ransomware works
Rotating the salts logs every user out, including any session the attacker still holds. That is the point.
5. Clean or rebuild — the honest test
| Situation | What to do |
|---|---|
| One shell found, no new users, no cron, no SSH keys, immutable infrastructure available | Rebuild from image, restore data only, scan uploads |
New local user, SSH key, cron job, systemd unit or ld.so.preload entry | Rebuild. Do not try to clean. |
| No shell found, but logs show code execution | Rebuild. You cannot enumerate the damage. |
| Only exposure, no execution evidence | Patch, rotate secrets, monitor for 7 days |
| Shared hosting | Ask to be moved to a fresh container; assume neighbours were exposed too |
Cleaning in place is defensible only when you can list every file the attacker could write, verify all of it against a known-good copy, and prove there is no persistence outside the web root. If any of those is “probably”, rebuild.
6. Watch for the return visit
Re-infection within a few days means persistence you missed, not bad luck. Minimum monitoring for a week: new files in the web root, new admin users, outbound connections from the web tier, and unexplained CPU spikes (miners are the most common payload).
7. Report, if it applies to you
In the US, the FBI asks for incidents via ic3.gov or a local field office. In the EU and UK, check your 72-hour breach-notification obligation if personal data may have been accessed — and with a memory-disclosure flaw, “may have been” is the honest standard. Tell your insurer inside the notification window in your policy, and tell your clients before they read about it.
Do not do this: do not paste your logs, database dumps or wp-config.php into a random online scanner, and do not install “nulled” cleanup plugins. Both are common second compromises. If you hire help, ask for a named person, a scope and a written report.
Want the whole sequence run for you?
Containment, entry-point analysis, shell hunt, credential rotation and a written record of what was found — for one site or a small estate.
Get help now Patch instead — read the runbook