WordPress 7.0.4 shipped with a fix for a code execution vulnerability rooted in the platform's handling of PostScript files. According to the disclosure, an attacker holding Author-level permissions or higher could abuse the flaw by uploading a weaponized PostScript (.ps) file, ultimately achieving code execution on the underlying server. While some early headlines characterized the issue as unauthenticated, the practical exploitation prerequisite — an authenticated Author account — matters enormously for your risk model: any site with untrusted contributors, compromised contributor credentials, or open registration misconfigurations is squarely in scope.
WordPress powers well over 40% of the web. Even a post-authentication code execution flaw in core is a mass-exploitation event waiting to happen, because Author-level credentials are routinely harvested through phishing, credential stuffing, and brute-force attacks against wp-login.php. Patch now, then hunt.
Technical Analysis
Affected Component and Root Cause Class
The vulnerable code path involves WordPress's media/file handling pipeline when processing PostScript files. PostScript is not an image format in the conventional sense — it is a Turing-complete page description language interpreted by engines such as Ghostscript. The security community has a long, well-documented history of memory corruption and sandbox-escape issues in PostScript interpreters, and Ghostscript in particular has been a recurring source of critical code execution flaws. When a web application passes an attacker-controlled .ps file to a server-side interpreter — for thumbnail generation, preview rendering, or format conversion via ImageMagick/Ghostscript delegates — the attacker's script executes with the privileges of the web server process.
The defender-relevant attack chain looks like this:
- Attacker authenticates to WordPress with an Author-level (or higher) account — legitimately held, phished, or brute-forced.
- Attacker uploads a crafted .ps file through the media library or a direct request to
wp-admin/async-upload.php/ the REST media endpoint (/wp-json/wp/v2/media). - Server-side processing invokes a PostScript interpreter (e.g.,
gs, or ImageMagick'sconvert/magickwith a PS delegate) against the uploaded file. - The malicious PostScript payload executes operating system commands as the web server user (
www-data,apache,nginx, or equivalent). - Post-exploitation follows: web shell deployment in
wp-content/uploads/, reverse shells, credential theft fromwp-config.php(database credentials, auth keys/salts), and lateral movement.
Affected Versions and Platforms
- Product: WordPress core, versions prior to 7.0.4
- Fixed version: WordPress 7.0.4
- Platforms: All self-hosted WordPress deployments (Linux/Apache/Nginx/PHP-FPM being the dominant stack; Windows/IIS deployments equally affected at the application layer)
- Prerequisite: Authenticated session with Author role or higher
Exploitation Status
At the time of writing, no public proof-of-concept or confirmed in-the-wild exploitation has been reported, and the issue has not been added to the CISA Known Exploited Vulnerabilities catalog. That window will not stay open long. WordPress core patches are reverse-engineered within hours of release — the diff between 7.0.3 and 7.0.4 is public, and the file-handling code path is a well-trodden target for exploit developers. Treat this as patch-this-week severity for any site with multiple content contributors, and patch-today severity for sites with open registration, membership functionality, or any history of contributor-account compromise.
Detection & Response
Detection for this threat clusters around three observable behaviors: PostScript files landing in WordPress upload directories, the web server process spawning a PostScript interpreter or unexpected child processes, and web shells appearing in wp-content/uploads/. The rules below are tuned for production WordPress hosting stacks.
---
title: Web Server Process Spawning PostScript Interpreter or Shell
description: Detects the web server or PHP-FPM worker process spawning Ghostscript, ImageMagick, or a command shell — consistent with exploitation of server-side PostScript processing in WordPress. Any shell child of a web server process is high-signal in production.
logsource:
category: process_creation
product: linux
detection:
selection_parent:
ParentImage|endswith:
- '/apache2'
- '/httpd'
- '/nginx'
- '/php-fpm'
- '/php-fpm8.1'
- '/php-fpm8.2'
- '/php-fpm8.3'
- '/php-cgi'
selection_child:
Image|endswith:
- '/gs'
- '/sh'
- '/bash'
- '/dash'
- '/zsh'
- '/python'
- '/python3'
- '/perl'
- '/nc'
- '/ncat'
- '/curl'
- '/wget'
condition: selection_parent and selection_child
falsepositives:
- Legitimate server-side document/image conversion pipelines that intentionally invoke Ghostscript from PHP
- Backup or maintenance plugins executing shell commands (should be inventoried and allowlisted explicitly)
level: high
---
title: PostScript File Written to WordPress Upload Directory
description: Detects creation of PostScript (.ps/.eps) files inside WordPress upload paths. WordPress core does not natively accept PostScript uploads for most configurations, so the presence of these files under wp-content/uploads is anomalous and warrants immediate triage.
logsource:
category: file_event
product: linux
detection:
selection_path:
TargetFilename|contains:
- '/wp-content/uploads/'
selection_ext:
TargetFilename|endswith:
- '.ps'
- '.eps'
- '.epsf'
- '.epsi'
condition: selection_path and selection_ext
falsepositives:
- Niche publishing workflows that legitimately handle PostScript assets (rare; verify with content team)
level: high
---
title: Script File Dropped in WordPress Uploads Directory
description: Detects PHP or other executable script files written into WordPress upload directories — a hallmark of post-exploitation web shell deployment following code execution through the media pipeline.
logsource:
category: file_event
product: linux
detection:
selection_path:
TargetFilename|contains: '/wp-content/uploads/'
selection_ext:
TargetFilename|endswith:
- '.php'
- '.phtml'
- '.phar'
- '.php5'
- '.php7'
- '.php8'
- '.py'
- '.pl'
condition: selection_path and selection_ext
falsepositives:
- Some plugins/themes legitimately ship PHP files in uploads subdirectories (e.g., index.php placeholders); index.php drops are common and can be filtered by filename
level: critical
// Hunt: Web server spawning interpreters/shells + PostScript artifacts in WordPress paths
// Assumes Linux syslog/auditd or Defender for Endpoint ingestion into Sentinel
// 1. Web server / PHP-FPM spawning Ghostscript or shells (process creation via auditd -> Syslog, or MDE)
DeviceProcessEvents
| where TimeGenerated > ago(7d)
| where InitiatingProcessFileName has_any ("apache2", "httpd", "nginx", "php-fpm", "php-cgi")
| where FileName has_any ("gs", "sh", "bash", "dash", "python", "python3", "perl", "nc", "ncat", "curl", "wget")
| project TimeGenerated, DeviceName, InitiatingProcessFileName, FileName, ProcessCommandLine, AccountName
| order by TimeGenerated desc;
// 2. Syslog/CEF-ingested auditd process events for Ghostscript execution under web context
Syslog
| where TimeGenerated > ago(7d)
| where SyslogMessage has_all ("wp-content", "uploads")
or (SyslogMessage has "gs" and SyslogMessage has_any ("www-data", "apache", "nginx"))
| project TimeGenerated, Computer, ProcessName, SyslogMessage
| order by TimeGenerated desc;
// 3. File events: PostScript or script files landing in uploads directories (MDE file events on Linux servers)
DeviceFileEvents
| where TimeGenerated > ago(7d)
| where FolderPath has "wp-content/uploads"
| where FileName endswith ".ps" or FileName endswith ".eps"
or FileName endswith ".php" or FileName endswith ".phtml" or FileName endswith ".phar"
| project TimeGenerated, DeviceName, FolderPath, FileName, InitiatingProcessFileName, InitiatingProcessCommandLine
| order by TimeGenerated desc
-- Hunt for PostScript files and web shells in WordPress uploads plus web-server-spawned processes
-- Deploy as a multi-artifact collection across WordPress hosting servers
-- Artifact 1: PostScript and script files in uploads directories (last 14 days)
SELECT FullPath, Size, Mtime, Atime, Ctime
FROM glob(globs='/var/www/**/wp-content/uploads/**/*.{ps,eps,php,phtml,phar}',
accessor='file')
WHERE Mtime > now() - 14 * 24 * 3600
ORDER BY Mtime DESC
-- Artifact 2: Live processes that are children of web server / PHP-FPM
SELECT Pid, Ppid, Name, Exe, CommandLine, Username, CreateTime
FROM pslist()
WHERE Username =~ 'www-data|apache|nginx'
AND Name =~ '^(gs|sh|bash|dash|python3?|perl|nc|ncat|curl|wget)$'
-- Artifact 3: Outbound network connections from web server user (reverse shell triage)
SELECT Pid, Name, Status, LocalAddress, RemoteAddress
FROM netstat()
WHERE Name =~ 'www-data|apache|nginx|php'
AND Status =~ 'ESTAB'
AND NOT RemoteAddress.IP =~ '^(10\\.|172\\.(1[6-9]|2[0-9]|3[01])\\.|192\\.168\\.|127\\.)'
#!/bin/bash
# WordPress 7.0.4 verification, patching, and compromise-assessment script
# Run on each WordPress hosting server. Requires WP-CLI and root/sudo for find/grep on web roots.
set -euo pipefail
WP_ROOT="${1:-/var/www/html}"
echo "[*] Target WordPress root: $WP_ROOT"
# 1. Check installed WordPress core version
echo "[*] Checking WordPress core version..."
wp core version --path="$WP_ROOT" --allow-root || { echo "[!] WP-CLI check failed"; exit 1; }
# 2. Update core to 7.0.4 (or latest) and verify checksums
echo "[*] Updating WordPress core..."
wp core update --path="$WP_ROOT" --allow-root
wp core update-db --path="$WP_ROOT" --allow-root
echo "[*] Verifying core file integrity..."
wp core verify-checksums --path="$WP_ROOT" --allow-root
# 3. Hunt for PostScript files in uploads (potential exploit payloads)
echo "[*] Searching for PostScript files in uploads..."
find "$WP_ROOT/wp-content/uploads" -type f \( -iname '*.ps' -o -iname '*.eps' -o -iname '*.epsf' -o -iname '*.epsi' \) -printf '%T+ %p\n' 2>/dev/null | sort -r || echo "[+] No PostScript files found"
# 4. Hunt for PHP files in uploads (potential web shells) modified in last 30 days
echo "[*] Searching for recently modified PHP files in uploads..."
find "$WP_ROOT/wp-content/uploads" -type f \( -iname '*.php' -o -iname '*.phtml' -o -iname '*.phar' \) -mtime -30 -printf '%T+ %p\n' 2>/dev/null | sort -r || echo "[+] No recent PHP files in uploads"
# 5. Block execution in uploads via .htaccess (Apache) if not already present
HTACCESS="$WP_ROOT/wp-content/uploads/.htaccess"
if [ ! -f "$HTACCESS" ]; then
echo "[*] Deploying execution-block .htaccess in uploads..."
cat > "$HTACCESS" <<'EOF'
<FilesMatch "\.(php|phtml|phar|php[0-9]|py|pl|ps|eps)$">
Require all denied
</FilesMatch>
EOF
else
echo "[*] .htaccess already present in uploads — verify it denies script execution"
fi
# 6. Audit Author-level and higher accounts for anomalies
echo "[*] Listing privileged users (author and above) with registration dates..."
wp user list --path="$WP_ROOT" --allow-root \
--role__in=author,editor,administrator \
--fields=ID,user_login,user_email,user_registered,roles --format=table
echo "[*] Done. Review findings above; investigate any unexpected files or accounts as an active incident."
Remediation
- Update WordPress core to 7.0.4 immediately. For managed fleets, use WP-CLI (
wp core update) or your management plane (MainWP, ManageWP, hosting-provider tooling). WordPress auto-updates typically cover minor/security releases — verify they actually fired; do not assume. - Verify integrity post-patch. Run
wp core verify-checksumsto confirm no core files were tampered with before or during the compromise window. - Audit Author-level and higher accounts. The exploitation prerequisite is an authenticated Author session. Enumerate every account with Author, Editor, or Administrator roles; disable dormant accounts; force password resets for contributor-tier users; enforce MFA (via a reputable plugin or SSO integration) for all roles above Subscriber.
- Restrict file upload types. WordPress does not permit .ps uploads by default for most roles, but plugins and custom
upload_mimesfilters frequently widen the allowed list. Audit active plugins and themefunctions.phpfor MIME-type filters that add PostScript or other interpreter-processed formats, and remove them unless there is a documented business need. - Disable execution in uploads. Ensure
wp-content/uploads/cannot execute scripts (.htaccessdeny rules for Apache;locationblocks withfastcgiexclusions for Nginx). This is defense-in-depth that blunts web-shell follow-on activity even if code execution occurs. - Constrain server-side interpreters. If Ghostscript/ImageMagick are installed but unused by your application stack, remove them. If they are required, apply a restrictive ImageMagick
policy.xmlthat disables the PS/EPS/PDF coders (<policy domain="coder" rights="none" pattern="PS" />and equivalents) — this is the classic mitigation for the entire class of PostScript-delegate attacks. - Review logs retroactively. Search web access logs for POST requests to
async-upload.phpand/wp-json/wp/v2/mediafrom unexpected IPs or accounts over the past 30–60 days, and correlate with the file-creation detections above. If you find .ps files in uploads or web-server-spawned shells, treat it as an active intrusion: preserve evidence, rotatewp-config.phpcredentials and salts, and follow your IR plan. - Harden authentication at the perimeter. Rate-limit or IP-restrict
wp-login.phpand XML-RPC where feasible; credential stuffing against contributor accounts is the most probable path to the prerequisite access this flaw requires.
No CVE identifier or CVSS score was published in the source disclosure at time of writing; monitor the official WordPress release notes and SecurityWeek coverage for updates, and re-check CISA KEV over the coming weeks.
Related Resources
Security Arsenal Penetration Testing Services AlertMonitor Platform Book a SOC Assessment vulnerability-management Intel Hub
Is your security operations ready?
Get a free SOC assessment or see how AlertMonitor cuts through alert noise with automated triage.