Join our Newsletter — 33% off our NHI Course
Home› Guides› PHP web shells: how to find them, remove…
Guide Incident Response & Forensics

PHP web shells: how to find them, remove them and stay clean

← All guides
By NHI Mgmt Group, edited by Lalit Choda Updated 2 November 2026 16 min read
On this page

A PHP web shell is a script planted on a web server that lets an attacker run commands through ordinary web requests, and on PHP hosting it is the most common way a single exploited bug turns into lasting control. PHP's flexibility works against defenders here: any writable directory that the interpreter will execute, any per-directory configuration file and any plugin installer can become a persistence point. This guide is a defender's reference for PHP environments specifically (Apache with mod_php, Nginx or Apache with PHP-FPM, WordPress, Drupal, Magento, Laravel and similar): the indicators to look for, how to hunt across files, logs and processes, how to check integrity against a known-good build, how to remove a shell without leaving the attacker inside, which credentials to rotate, and the PHP and server settings that make the next shell harder to plant or run. It contains no shell code. For the incident workflow, roles and communications, use the Web Shell Response Playbook; this page is the PHP-specific technical depth behind it.

Key takeaways

  • Compare against known-good, do not trust timestamps. NSA and the Australian Signals Directorate put comparison with a verified clean copy first, and warn that attackers alter file times (ATT&CK T1070.006 Timestomp).
  • Watch the PHP process, not just the files. A PHP-FPM worker or Apache child launching a shell, network tools or reconnaissance commands is the strongest single signal on Linux.
  • Look beyond .php files. Per-directory configuration (.user.ini under FastCGI, .htaccess under mod_php), backdoor plugins and hidden admin accounts give the same access and survive file clean-ups.
  • Removal is the start, not the end. NSA and ASD stress that removing a shell without scoping the intrusion lets the attacker return; rebuild from clean code and rotate every secret the PHP user could read.
  • Stop PHP executing where users can write. The most effective hardening is a web root the PHP user cannot write to and upload directories where PHP will not run; disable_functions and open_basedir help but PHP's own manual says they are not security boundaries.

How PHP web shells get in and where they hide

ATT&CK tracks web shells as T1505.003 under persistence. The shell is rarely the entry point: it is planted after another weakness, and knowing the route tells you where else to look.

Entry routeTypical PHP exampleWhere to look first
Exploited public-facing application (T1190)Vulnerable plugin, theme, CMS core or the PHP runtime itself, as with the PHP2Shell campaignAccess logs around the vulnerable endpoint; files created shortly after
Unrestricted file uploadUpload form or media library that accepts a file the server later executes as PHPUpload and media directories, cache and temp directories inside the web root
Stolen deployment or admin credentials (T1078)Leaked sFTP, SSH, control-panel or CMS administrator passwordssFTP and control-panel logs, CMS admin logins, new plugin installs
Compromised update or management channelStolen remote-management keys used to push a "plugin" through the normal installerPlugin and must-use plugin directories, plugin install logs, new admin users
Supply chainBackdoored package or nulled (pirated) theme or pluginThird-party code compared against the vendor's published release

The UpdraftCentral Key Theft 2026 case shows the last two rows: stolen connection keys were used to send validly signed plugin installs, the backdoor plugins created hidden accounts, and the advice was to treat affected sites as fully compromised and restore from a backup taken before the theft. No vulnerability was exploited and no standalone PHP file had to be dropped. See the PHP2Shell guide for a runtime-level entry route and the PHP and WordPress Security Guide for platform hardening in general.

Common hiding places

  • Upload, cache and temp directories inside the document root, where PHP files have no business being.
  • Plugin, theme and module directories, including must-use plugin folders that load automatically and do not appear in the normal plugin list.
  • Legitimate files with appended code, such as a theme's functions file or a core bootstrap file, so the file name looks normal.
  • Per-directory configuration: auto_prepend_file and auto_append_file are INI_PERDIR settings, so they can be set in a .user.ini (read by the CGI and FastCGI SAPI, scanned from the script's directory up to the document root) or in .htaccess under the Apache module, causing a hidden file to run before or after every page.
  • Files with misleading extensions or names that the server is configured to execute as PHP, and files named to look like images, logs or licence files.
  • The database: CMS options, widgets or plugin settings that store code later evaluated by the application, and administrator accounts that need no file at all.

Indicators of a PHP web shell

Indicator typeWhat to look forReliability
Integrity differenceFiles added or changed compared with the clean release or your deployment artefactHigh; every difference needs review
Process lineagephp-fpm, apache2 or httpd spawning a shell (T1059.004), network utilities, package managers or reconnaissance commandsHigh on servers where the application never does this
Rare URIsPHP files requested by very few user agents or IP addresses, often with missing or unusual referer headersMedium; NSA's log scripts always return results, so verify each
Unexpected outbound connectionsThe web server connecting out to unfamiliar hosts, or downloading tools (T1105)Medium to high where egress is normally limited
File content patternsDynamic code execution and decoding functions combined with request parameters; very long encoded strings; matches from YARA rule setsCore signatures catch known unmodified shells; extended ones catch obfuscation but raise false positives
BehaviourUnusually large responses, off-peak access, requests from unexpected geographiesLow on its own; NSA calls these subjective
Account and config changesNew CMS administrators, new SSH keys for the web user, new cron entries, modified .user.ini or .htaccessHigh

Hunting: files, logs and processes

Files and integrity

  1. Get a trusted baseline. Use your deployment artefact or a fresh download of the exact versions of the CMS, plugins and themes. NSA's Mitigating-Web-Shells project shows a recursive directory diff on Linux and a PowerShell directory checker on Windows for this comparison.
  2. Verify platform checksums. Most CMSs and package managers can verify installed files against published hashes (for example WP-CLI's core and plugin checksum verification, or the distribution's package verification for system PHP files). Treat any mismatch as a lead.
  3. List PHP where it should not be. Search upload, media, cache and temp directories for any file the server will execute as PHP. On most sites the expected count is zero.
  4. Review per-directory config. Find every .user.ini and .htaccess and check for auto_prepend_file, auto_append_file or handler directives that make new extensions executable.
  5. Scan with signatures. Run the NSA project's YARA rules or your EDR's scanner over the web root and backups. Core rules have few false positives; extended rules surface obfuscated code for manual review.
  6. Do not rely on modification times. NSA and ASD note attackers may timestomp; use integrity comparison and file-creation events instead.

Web server logs

  • Rare-URI analysis: rank PHP URIs by the number of distinct client IPs and user agents. NSA provides a Splunk query and a Python script for Apache logs. Investigate the tail, especially POST requests to files outside normal routes.
  • Timeline around entry: for each suspicious file, find the first request to it and the requests just before it from the same source; that often reveals the upload or exploit.
  • Control-panel and sFTP logs: uploads by deployment accounts outside release windows, and logins from new locations.
  • Retention: make sure access logs are retained and shipped off the host for long enough to cover the likely dwell time.

Processes and the host

  • Audit what the web user runs: the NSA project includes Linux auditd guidance for logging commands executed by the Apache user. Apply the same to the PHP-FPM pool users and alert on reconnaissance tools.
  • EDR parent-child rules: alert when php-fpm, apache2 or httpd is the parent of a shell or interpreter. Many PHP applications never legitimately do this.
  • Network: NSA and ASD recommend looking for unexpected network flows, including hosts answering HTTP that should not be web servers. The project includes a Snort rule for this pattern.
  • Persistence outside the web root: cron entries and systemd units created by the web user, SSH keys in its home directory, and new local accounts.

Removing a PHP web shell safely

NSA and ASD are clear that defenders should not stop at removing the shell: they need to determine how far the attacker moved, or incomplete clean-up lets them back in. Coordinate the steps below with the incident lead using the Web Shell Response Playbook.

  1. Preserve evidence first. Copy the suspicious files, the per-directory config, the web, PHP-FPM and system logs and, where possible, a disk and memory image before changing anything. See the Evidence Handling and Chain of Custody Guide.
  2. Contain without tipping off. Block the shell's URIs at the WAF or reverse proxy, restrict outbound traffic from the host, and put the site in maintenance mode if needed. Avoid deleting files one at a time while the attacker is still watching.
  3. Scope the intrusion. Determine the entry route, every file and account the attacker created, what data and secrets they could read as the PHP user, and whether they reached the database server, other sites on the same host, or the internal network.
  4. Rebuild, do not clean. Redeploy the application from a trusted artefact onto a clean or rebuilt host, rather than editing infected files in place. Restore content (uploads, database) from a backup taken before the earliest evidence of compromise, and check that backup for the same indicators.
  5. Close the entry route. Patch or remove the vulnerable component, fix the upload handling, or revoke the stolen management keys, before the site goes back online.
  6. Rotate credentials (next section), then remove CMS accounts, SSH keys, cron jobs and plugins the attacker added.
  7. Return to service under watch. Turn on heightened monitoring for at least the next few weeks: integrity checks, process alerts and rare-URI reviews daily.

Rollback: keep the preserved compromised image offline. If the rebuild breaks the site, roll back to the previous clean release, never to the compromised copy.

Credentials to rotate

A PHP shell runs as the PHP user and can read everything that user can, which on most sites includes the application's configuration files and environment (ATT&CK T1552.001 Credentials In Files). Assume all of it was read.

SecretUsually stored inAction
Database credentialsCMS config file, framework .env, environment variablesCreate a new database user and password, update the app, drop the old user; review database for added admin rows
Application secret keys and saltsFramework app key, CMS authentication saltsRegenerate; this ends existing sessions and invalidates forged cookies
Third-party API keysPlugin settings in the database, config filesRotate at each provider: payment, email, storage, search, analytics
Cloud and storage keysConfig, environment, backup plugin settingsRevoke and reissue; check provider logs for use from unknown addresses
sFTP, SSH and control-panel credentialsHosting account, deployment toolsReset; replace passwords with keys where possible; remove unknown keys
TLS private keysWeb server config readable by the serviceReissue certificates where the key was readable by the PHP user
CMS administrator accountsDatabaseReset passwords, end sessions, reset two-factor enrolment, remove unknown admins

The GoDaddy Managed WordPress Breach 2021 shows the scale of this list on hosting: sFTP, database and admin passwords and some SSL private keys were all exposed and had to be reset or reissued together. Use the Secrets Rotation Runbook Template to work through it, and check the Incomplete rotation breaches guide for what happens when one key is missed.

Where identity fits

Every secret in the table above is a non-human identity: a database account, an API key, a cloud key, a deployment credential. Web shells matter so much because PHP applications hold these identities in readable files. Reduce the blast radius by giving each site its own database user with only the privileges it needs, preferring short-lived or workload-issued cloud credentials over static keys, keeping secrets outside the web root, and inventorying which keys each site holds so rotation is a list, not a search. See the Environment Variables and .env Files guide and the Secrets Management Guide.

Hardening PHP servers against web shells

ControlSetting or approachWhat it stops, and its limits
Read-only codeApplication code owned by a deploy user; PHP user can read but not write the web rootNSA and ASD recommend preventing web applications writing to web-accessible directories. Stops most shell drops; needs a deployment process instead of in-browser updates
No PHP in writable directoriesWeb server rule denying PHP execution in upload, cache and temp paths; uploads stored outside the document root where possibleStops uploaded files running even if a filter is bypassed
Per-directory config locked downSet user_ini.filename to empty if .user.ini is not used; restrict AllowOverride under ApacheRemoves the auto_prepend_file persistence route
disable_functionsphp.ini only, for command-execution functions the application does not useRaises the bar; PHP's manual warns it can be circumvented and is not sufficient on shared hosting
open_basedirLimit file access to the application and its temp directoryThe manual calls it "just an extra safety net"; it does not restrict Unix domain sockets
expose_php = Offphp.iniStops advertising the PHP version in headers; reduces targeting, not a fix
Separate pools per siteOne PHP-FPM pool and Unix user per siteA shell on one site cannot read another site's files or secrets
File integrity monitoringFIM or HIPS rules on web directories, starting in alert mode then blockingDetects or blocks new files; tune exceptions for legitimate updates
WAF with OWASP Core Rule SetIn front of the applicationMay stop initial exploits and malicious uploads; NSA notes it is unlikely to catch web shell traffic itself
Egress restrictionAllow the web server to reach only required destinationsLimits tool downloads and data theft after compromise
Fast patchingAutomatic updates where safe; supported PHP versions onlyNSA and ASD note attackers often exploit web vulnerabilities within 24 hours of release

See the Web Application Firewall Guide and the File Integrity Monitoring Guide for those controls in depth.

Small sites versus large estates: a single business site on managed hosting can get most of the benefit from read-only code, no PHP in uploads, automatic updates and the host's malware scanning. Agencies and hosting providers running many sites need per-site pools and users, central log collection, fleet-wide integrity checks and a rotation process that can reset credentials for hundreds of sites at once.

Rolling out detection and hardening

  1. Inventory every PHP site, its PHP version, CMS, plugins, hosting model, and the secrets it holds.
  2. Baseline each site's code from its deployment artefact and start daily integrity comparison.
  3. Pilot read-only code and no-PHP-in-uploads on a staging copy; test updates, uploads and admin functions.
  4. Turn on process and file monitoring in alert-only mode, tune for two to four weeks, then switch file rules to blocking where the deployment process allows.
  5. Roll out by site group, keeping the previous web server and PHP configuration for rollback.
  6. Exercise the removal and rotation steps once a year on a test site.

Detection and measurement

MetricWhat it showsTarget
Sites with daily integrity comparison against a known-good buildCoverage of the strongest detection100 percent of internet-facing PHP sites
Sites where the PHP user cannot write to code directoriesPrevention coverageRising each quarter, all new sites
PHP files found in upload or cache directoriesExposure to upload-based shellsZero
Web-server-spawned shell alerts investigated within one working daySOC response to the strongest host signal100 percent
Secrets rotated after a confirmed shell, as a share of secrets the PHP user could readCompleteness of recovery100 percent
Sites on supported PHP versionsPatch exposure100 percent

Common failure patterns

  • Deleting the file and moving on. The entry route stays open and the attacker's other footholds remain, exactly what NSA and ASD warn against.
  • Cleaning only the file system. Backdoor plugins, hidden admin accounts and database-stored code survive a file scan, as the UpdraftCentral case showed.
  • Restoring a compromised backup. Restoring from a backup taken after the shell arrived reinstalls it; check the backup date against the earliest evidence.
  • Skipping rotation. Database passwords, app keys and API keys in readable config files keep working for the attacker after the shell is gone.
  • Trusting disable_functions. PHP's own documentation says it can be circumvented; it is a speed bump, not a wall.
  • Shared PHP user across sites. One compromised site on a shared server reads every other site's configuration.

Framework mapping

FrameworkReferenceRelevance
MITRE ATT&CKT1505.003, T1190, T1078, T1059.004, T1105, T1552.001, T1070.006Web shell persistence, entry routes, command execution, tool transfer, credential theft and timestomping
NIST SP 800-53 Rev 5SI-7, SI-7(1), CM-5Integrity checks on web code; restricting who can change it
NIST SP 800-53 Rev 5SI-3, SI-4, AU-12Malicious code scanning, host and log monitoring
NIST SP 800-53 Rev 5IR-4, RA-5, SC-7Incident handling, vulnerability scanning, egress and boundary controls
NIST CSF 2.0DE.CM-09, PR.PS-02, RC.RP-01Monitoring runtime environments, maintaining software, executing recovery
ISO/IEC 27001:2022 Annex AA.8.7 Protection against malware; A.8.8 Management of technical vulnerabilities; A.5.26 Response to information security incidentsPrevention, patching and response

Practitioner checklist

  • Keep a known-good build for every PHP site and compare production against it daily.
  • Make code directories read-only to the PHP user and block PHP execution in upload and cache paths.
  • Review every .user.ini and .htaccess for prepend, append and handler directives.
  • Alert when php-fpm, apache2 or httpd spawns a shell or network tool.
  • Run rare-URI analysis on access logs weekly and ship logs off the host.
  • On a confirmed shell, preserve evidence, scope, rebuild from clean code and restore pre-compromise content.
  • Rotate every secret the PHP user could read, and remove attacker accounts, keys, plugins and cron jobs.
  • Run one PHP-FPM pool and user per site, and keep PHP on supported versions.

Standards and references

Related NHI Mgmt Group resources: Web Shell Response Playbook · PHP2Shell · PHP and WordPress Security Guide · Secrets Rotation Runbook Template · File Integrity Monitoring Guide

Free weekly newsletter

Subscribe to the NHI & AI Identity Journal

The latest on NHI and Agentic AI security – articles, research, breaches, news and events every week.

Bonus 33% off our NHI Course when you subscribe.

NHIMG Editorial Note
Researched and written by the NHI Mgmt Group editorial team using AI tools, under the editorial direction of Lalit Choda. Facts are drawn from the sources listed on this page and checked by our automated quality process. Last updated 2 November 2026. Spotted an error? Use our contact page.
NHI Mgmt Group, the independent authority on Non-Human Identity, IAM and Agentic AI security. nhimg.org