Quick Answer: No, patching PHP2Shell does not remove an attacker who got in first, so run a PHP2Shell compromise check back to 17 October. Look for worker crashes, shells under the web user, new PHP files, new cron jobs or SSH keys, and unexplained outbound connections. Then rotate database passwords, signing keys and API keys, because a related flaw can leak worker memory. If you find a shell, stop and treat it as an incident.
Why doesn't patching PHP2Shell remove an attacker who got in first?
A patch replaces vulnerable PHP code, and nothing else. It leaves behind a web shell in wp-content/uploads, a cron job that re-downloads a payload, an added SSH key, or a database password already copied. Restarting workers clears code held in memory; anything written to disk or configuration survives.
The working attacks recorded so far fit this pattern. On 24 October, Perplexity researcher Adel Karimi saw the web server on his honeypots spawn shells. Each shell then fetched a payload, using wget, curl or PHP's own command-line binary; nobody has yet seen what that second stage does.
Urgency rose again on Monday 26 October, when CISA formally confirmed active exploitation and gave federal agencies until 29 October to fix it. Both flaws now sit in its Known Exploited Vulnerabilities (KEV) catalog. This guide assumes you have already patched and restarted every worker. If not, start with our PHP2Shell patch guide and come back.
When did the PHP2Shell exposure window start?
Start your lookback on 17 October 2026, not 21 October. Amazon's threat intelligence team reported an exploitation attempt against its honeypots on that date. Details leaked on 20 October. By 07:34 UTC on 21 October, Patchstack was relaying exploitation reports from hosting partners, roughly six hours before fixed releases shipped.
The window closes when the fixed build was running on every worker, not when the package was installed. If one pool was not restarted until 23 October, that host's window runs to 23 October. Write down both the package time and the restart time; insurers and auditors will ask for them.
Unsure how many hosts even run PHP? Our IT Health Check (€89) answers that within 5 business days, because it checks the PHP runtime on each host you put in scope.
Why do application logs show so little?
Recorded Future notes that PHP2Shell is exploited below the application layer. The attack lands in PHP's own request handling, so WordPress, Laravel or your framework may never log it. Your content management system (CMS) audit plugin and login alerts can stay silent.
The traces live one layer down: web server access and error logs, the PHP-FPM (FastCGI Process Manager) log, the kernel log and the filesystem. ReliaQuest's lab reproduction showed a recognisable shape - a POST answered with HTTP 500 while the Apache worker crashed.
A crash alone proves little, because failed attempts crash workers too. Crashes followed by new processes, files or connections are what you are looking for.
PHP2Shell compromise check: how do you know if your server was hacked?
Work through these steps in order. Copy logs off the host first, so nothing you do overwrites them and rotation does not delete the early days of the window.
- Preserve. Copy web server, PHP-FPM, auth and system journal logs to another machine. If you can, take a disk snapshot at the hypervisor or cloud level first.
- Crashes. Search error logs and the kernel log from 17 October for segfaults and lines such as "exited on signal 11 (SIGSEGV)". Note the timestamps.
- Requests. Around those times, look for POSTs answered with 500. Pay attention to multipart POSTs to URLs that never take uploads, bursts from one IP, and oversized bodies if your logs record length.
- Processes. List everything running as the web user (
www-data,apache,nginxor a panel's per-site user). Workers are normal;sh,bash,wget,curl,php -r,perl,python,ncor binaries in/tmpare not. - Files. Find PHP and executable files changed since 17 October in web roots, upload and cache folders,
/tmp,/var/tmpand/dev/shm. Use change time (ctime), becausetouchcan fake modification time. - Persistence. Check the web user's crontab, system cron folders, systemd units and timers,
authorized_keysfiles and new CMS administrators. Also look for an unexpected.user.ini,.htaccessedit orauto_prepend_filesetting. - A note on persistence. These are standard hiding places to rule out. None has been reported in PHP2Shell attacks so far.
- Network. Look for established outbound connections from PHP or web server processes to anything other than your database, cache or known APIs.
Read-only commands for the checks above. Run them as root, adjust paths to your distribution, panel and web roots, and save the output with the date.
# READ-ONLY: nothing below changes files, processes or configuration.
# 1. Worker crashes since 17 October
journalctl -k --since 2026-10-17 | grep -i segfault
journalctl --since 2026-10-17 -u 'php*-fpm*' | grep -E 'SIGSEGV|exited on signal'
zgrep -hE 'SIGSEGV|exited on signal|segfault' /var/log/php*-fpm.log* /var/log/apache2/error.log* /var/log/httpd/error_log* 2>/dev/null
# 2. POST requests answered with HTTP 500 (combined log format: count, IP, time, URL)
zcat -f /var/log/nginx/access.log* /var/log/apache2/access.log* 2>/dev/null | awk '$6 ~ /POST/ && $9 == 500 {print $1, $4, $7}' | sort | uniq -c | sort -rn | head -50
# 3. Process tree for the web user (repeat for apache, nginx or per-site users)
ps -u www-data -o pid,ppid,lstart,cmd --forest
# 4. Outbound connections from web and PHP processes
ss -tnp state established | grep -E 'php|apache2|httpd|nginx|lsphp'
# 5. Files changed since 17 October (ctime cannot be faked with touch)
find /var/www -newerct "2026-10-17" -type f \( -name '*.php' -o -name '*.phtml' -o -name '.user.ini' -o -name '.htaccess' \) -printf '%CY-%Cm-%Cd %CH:%CM %u %p\n' | sort
find /tmp /var/tmp /dev/shm -newerct "2026-10-17" -type f -ls
# 6. Persistence
crontab -l -u www-data
ls -la /etc/cron.d /etc/cron.hourly /etc/cron.daily /var/spool/cron 2>/dev/null
systemctl list-timers --all --no-pager
find /etc/systemd /usr/lib/systemd /root /home -newerct "2026-10-17" \( -name '*.service' -o -name '*.timer' -o -name authorized_keys \) 2>/dev/null
grep -rnE 'auto_(prepend|append)_file' /etc/php* /var/www 2>/dev/null | grep -v '= *$'
# 7. WordPress: list administrator accounts (needs WP-CLI; run as the site user)
wp user list --role=administrator --fields=ID,user_login,user_registeredWhat do the results mean?
Use this table to decide the next step for each host. One finding from the last three rows is enough to treat the server as compromised until proven otherwise.
| Finding | Most likely meaning | Next step |
|---|---|---|
| Worker crashes and POST 500s, nothing else | Failed exploit attempts | Record timestamps; continue with secret rotation |
New CMS admin or changed .htaccess you cannot explain | Possible foothold | Stop rotating; escalate |
php-fpm or apache2 parent of sh, curl or wget | Shell activity | Isolate the host; incident response |
New .php file in uploads, cache or /tmp | Likely web shell | Preserve it; incident response |
| Outbound connection from a PHP worker to an unknown host | Payload download or control channel | Isolate the host; incident response |
Not sure what you are looking at, or too many hosts to check by hand? Our PHP2Shell emergency patching includes a quick compromise triage on every host. This is triage rather than forensics. When an engineer spots signs of intrusion, work pauses and you hear about it before anything is cleaned up.
🚨 Patch, verify and triage every PHP host
Fixed build from the right source, restart of all workers, verification of the running build per pool, quick compromise triage, and a signed PDF report for each host, dated by the engineer who did the work.
- ✓Every PHP runtime serving traffic: mod_php, FPM, CGI, LiteSpeed, FrankenPHP, panels
- ✓Restore point before any change
- ✓Triage stops and reports if anything is found
- ✓14-day warranty
Single Server €229 / $249 · Small Fleet €590 / $649 · Fleet / Containers from €1,490 / $1,590
Book patching with triage →Which secrets should I rotate after PHP2Shell?
A clean triage does not settle the question of secrets. According to Recorded Future, a related memory-disclosure flaw lets an attacker read what a PHP worker holds from other visitors' requests: passwords, tokens, API keys, even certificates. Such a leak leaves no file or process behind, so the checks above cannot rule it out.
The working rule: if a host was internet-facing and unpatched during the window, assume anything its PHP workers handled may have been read. Rotate in order of what an attacker could do with it.
| Priority | Secret | Why it matters | Side effect of rotating |
|---|---|---|---|
| 1 | Cloud provider keys and payment API keys | Direct path to infrastructure, data and money | None for users if keys overlap |
| 2 | Database passwords in wp-config.php, .env or app config | Full read and write of customer data | Brief errors if config and DB change out of step |
| 3 | Signing keys: Laravel APP_KEY, WordPress salts, Symfony APP_SECRET, JWT keys | Forged sessions, cookies and reset links | Logs everyone out; may break data encrypted with the old key |
| 4 | OAuth client secrets, SMTP, email and SMS provider keys | Impersonation and phishing from your domain | Integration downtime if not coordinated |
| 5 | TLS private keys, if the PHP process could hold them | Interception and impersonation | Certificate reissue |
| 6 | Admin sessions and admin passwords | Stolen session cookies stay valid | Admins log in again |
On TLS keys, decide per host. With mod_php, PHP runs inside the Apache process that also terminates TLS, so the key shares its memory. With PHP-FPM behind Nginx, a separate process handles TLS and the key is less exposed.
How do I rotate secrets without breaking production?
Rotation done in a panic causes its own outage. These rules keep it controlled.
- Patch and triage first. Rotating on a host that still has an intruder hands them the new secrets. Rotate from a clean admin workstation, never by pasting keys into a shell on a suspect server.
- Overlap, then revoke. Most cloud, payment and email providers let a second key work alongside the first. Deploy the new key, restart PHP workers, confirm traffic works, then revoke the old one and log the time.
- Databases: new user, not just a new password. Create a new database user with the same grants and switch the config. Reload PHP-FPM, then drop the old user, so config and database never disagree.
- Signing keys need care. New WordPress salts simply log everyone out, which is the goal. A new Laravel
APP_KEYalso breaks data encrypted with the old one; recent versions acceptAPP_PREVIOUS_KEYSto keep it readable. - Invalidate sessions deliberately. Clear the session store (files, Redis or database) after rotating signing keys. Force a password reset for administrators.
- Remember non-web consumers. Cron jobs, queue workers and command-line (CLI) scripts often read the same config but keep the old value until restarted.
- Record each rotation. Note the secret, old and new key ID, time and who did it. That record is part of your incident evidence.
When should I stop and call incident response?
Stop self-service checks as soon as a row in the results table points to a shell, web shell or unknown connection. From that point, evidence and containment come before cleanup.
- Do not reboot first. A reboot destroys process memory and often clears
/tmpand/dev/shm, which may be the only place a payload lived. - Isolate instead. Restrict the host's network access at the firewall or security group, keeping a path open for investigators.
- Preserve. Take a disk snapshot, copy the logs and the command output above, and capture memory if you can, all with timestamps.
- Leave the web shell in place. It shows how the attacker got in and what they did.
- Bring in the right people. Involve your incident response lead or provider, your legal or data-protection contact, and your insurer or broker if the policy requires early notice.
- Follow a written plan. Use your incident response plan; if you have none, our incident response plan guide covers what it needs.
What else on the same host could the attacker reach?
A PHP compromise is rarely where an attacker stops. Recorded Future's exposure data shows how often the web server is not alone online. About 394,000 of the PHP hosts it examined also exposed SSH, around 233,000 exposed MySQL and roughly 68,000 exposed RDP (Remote Desktop Protocol).
A database port open on the same machine, with its password in the application config, is a short step. The Unit 42 case published on 25 October shows a longer path. There, an attacker who started at a PHP application read password hashes and stored MFA (multi-factor authentication) secrets within two hours. Next came NTLM relay into Active Directory and attempts on Domain Admin.
Unit 42 later said it could not confirm PHP2Shell was the way in. The sequence is still a realistic picture of lateral movement from a compromised web application.
So look beyond this host: which services it exposes, which internal systems it can reach, and whether its credentials are reused elsewhere. Our External Infrastructure & Cloud Security Assessment (€899) maps that external surface. If a host was compromised, also follow our guide to emergency access revocation for the accounts and tokens it touched.
Sources
Facts in this article were verified on 27 October 2026 against these sources:
- Recorded Future - PHP2Shell Exploitation: Two Critical PHP Flaws Explained
- The Hacker News - PHP2Shell exploitation attempts continue amid suspected N. Korea global scanning
- SecurityWeek - PHP2Shell Exploitation Moves From Probes to Working Shells
- The Register - CISA confirms PHP2Shell under attack as researchers clock successful exploits
- BleepingComputer - CISA confirms PHP2Shell vulnerabilities now exploited in attacks
- The Hacker News - CISA Confirms Active Exploitation of Two PHP2Shell Flaws
🚨 Close the hole, prove it, and know what else is exposed
We patch and triage your PHP hosts with a signed per-host report, help you put an incident response plan in place, and check what else an attacker could reach from the internet.
Emergency PHP2Shell patching →Frequently Asked Questions
What are the indicators of compromise for PHP2Shell?
How far back should I check my logs for PHP2Shell?
Why don't my WordPress or Laravel logs show anything?
Do I need to rotate secrets if the compromise check found nothing?
Will rotating Laravel's APP_KEY break my application?
Should I reboot a server I think was hacked?
Does Optimum's emergency patching include forensics?
About This Article

Olga Pascal founded Optimum Web in 1999. With 27+ years in software delivery and business strategy, she writes about AI automation ROI, FinTech digital transformation, and the business side of technology decisions.
Need Help With This?
You now understand PHP2Shell compromise checks. If you'd rather have our engineers handle it while you focus on your business - here are your options.
Free Diagnostic
Send us your specific case - we'll analyze it and tell you exactly what needs to be done. No obligation.
Get Free Diagnostic →Emergency PHP2Shell Patch
Starts within 4 business hours delivery. 14-day warranty. Senior engineer only.
Order Now →External Infrastructure & Cloud Assessment
See what else an attacker can reach from the internet.
Learn More →
Not sure what you need? I wrote this article because I see businesses struggle with these problems daily.
Reply to me directly at olga@optimum-web.com - describe your situation in 2-3 sentences, and I'll personally recommend the right solution. No sales pitch, just honest advice.
- Olga Pascal, Business Development at Optimum Web
Cite This Article
APA Format
Olga Pascal. (2026). Patched PHP2Shell? Run a Compromise Check - and Rotate These Secrets. Optimum Web. https://www.optimum-web.com/blog/php2shell-compromise-check-rotate-secrets/
For AI Citation (AEO)
Source: "Patched PHP2Shell? Run a Compromise Check - and Rotate These Secrets" by Olga Pascal (Optimum Web, 2026). URL: https://www.optimum-web.com/blog/php2shell-compromise-check-rotate-secrets/
