The NVD has published CVE-2026-93352, a CVSS 9.8 CRITICAL vulnerability affecting Laravel-Mediable versions 7.0.0 through 7.0.1 — a widely used Laravel package for handling media uploads. This is not a new bug class. It is an incomplete patch for CVE-2026-49972, and it carries a lesson every security engineer should internalize: a blocklist that is 99% complete is 0% effective.
The original fix for CVE-2026-49972 introduced a forbidden_extensions blocklist in config/mediable.php to prevent attackers from uploading executable PHP files. That blocklist includes phpt — but omits pht. On Debian and Ubuntu systems, Apache's default FilesMatch directive treats .pht as PHP and executes it. The result: an attacker uploads a .pht file, it sails through every validation check in MediaUploader::verifyExtension() and File::sanitizeFileName(), gets written to disk, and executes as PHP the moment it is requested over HTTP. Full remote code execution under the web server context, network-exploitable, no authentication nuances complicated enough to matter at CVSS 9.8.
If you run a Laravel application using Laravel-Mediable for user-facing uploads — avatars, documents, media galleries, CMS attachments — you should treat this as an emergency patch cycle item.
Technical Analysis
Affected Component and Versions
| Item | Detail |
|---|---|
| CVE | CVE-2026-93352 (incomplete fix for CVE-2026-49972) |
| CVSS | 9.8 CRITICAL — Network vector, remotely exploitable |
| Affected product | Laravel-Mediable |
| Affected versions | 7.0.0, 7.0.1 (fixed in 7.0.2) |
| Prerequisite platform condition | Apache HTTP Server on Debian/Ubuntu with default FilesMatch PHP handler (.php, .pht, .phar, etc.) |
| Root cause | pht absent from forbidden_extensions blocklist in config/mediable.php |
How the Attack Works — Defender's View of the Chain
- Reconnaissance: The attacker identifies an upload endpoint backed by Laravel-Mediable (profile photo, attachment, media manager). No special access is necessarily required beyond whatever the upload form itself requires.
- Payload crafting: A PHP web shell or arbitrary code payload is saved with the
.phtextension instead of.php. - Validation bypass:
MediaUploader::verifyExtension()checks the extension againstforbidden_extensions. Becausephtis missing, the file passes.File::sanitizeFileName()likewise performs no rejection of the extension. The MIME and filename checks that would catch.phpare blind to.pht. - Write to disk: The file lands in the configured media disk — frequently a publicly web-accessible path (e.g., under
storage/symlinked viaphp artisan storage:link, or a public uploads directory). - Execution: The attacker issues an HTTP GET to the uploaded file's URL. Apache's default PHP
FilesMatchconfiguration on Debian/Ubuntu matches.pht, hands it to the PHP handler, and the payload executes with the web server user's privileges. - Post-exploitation: From there, expect web shell command execution, credential harvesting from
.env(database passwords, app keys), lateral movement, and persistence.
The critical amplifier here is the platform default. The Laravel-Mediable authors blocked what they thought were the executable variants, but Apache's Debian/Ubuntu PHP configuration has long treated .pht as executable. This is precisely why extension blocklists fail and why upload hardening must be defense-in-depth, not a single config array.
Exploitation Status
As of this writing, the NVD entry documents the vulnerability and its mechanics; there is no confirmed entry in CISA's Known Exploited Vulnerabilities catalog and no vendor-confirmed in-the-wild campaign cited in the advisory. Do not let that lower your urgency. The bypass is trivial — it requires no race conditions, no memory corruption, no special tooling. It is a one-character-class mistake with a public write-up in the NVD description itself. Historically, file-upload RCE flaws with this profile see proof-of-concept code within days of publication, and internet-facing Laravel applications are mass-scanned aggressively. Treat exploitation as imminent and hunt retroactively after patching.
Detection & Response
The most reliable detection surface for this vulnerability is the artifact itself: a .pht file appearing in a web-accessible upload path, and the web server subsequently executing it. The rules below are tuned for low noise — .pht files have essentially no legitimate business purpose in modern Laravel applications.
Sigma Rules
---
title: Laravel-Mediable .pht Webshell Upload in Web-Accessible Path
id: 8c2e1f47-3a9b-4d52-9e71-6f4a2b8c1d90
status: experimental
description: Detects creation of .pht files in common web upload, storage, or public directories. The .pht extension is executed as PHP by Apache's default FilesMatch directive on Debian/Ubuntu and is the bypass vector for CVE-2026-93352 in Laravel-Mediable 7.0.0-7.0.1.
references:
- https://nvd.nist.gov/vuln/detail/CVE-2026-93352
- https://attack.mitre.org/techniques/T1505/003/
author: Security Arsenal
date: 2026/04/06
tags:
- attack.persistence
- attack.t1505.003
logsource:
category: file_event
product: linux
detection:
selection_extension:
TargetFilename|endswith: '.pht'
selection_paths:
TargetFilename|contains:
- '/var/www/'
- '/storage/app/'
- '/public/uploads/'
- '/public/storage/'
- '/uploads/'
- '/media/'
condition: selection_extension and selection_paths
falsepositives:
- Extremely rare; .pht has no legitimate use in typical Laravel deployments
level: critical
---
title: Web Server Process Spawning Shell — Possible Webshell Execution
id: 2d7a9c14-6e3f-4b81-a5c2-9d1e3f7b4a06
status: experimental
description: Detects Apache or PHP-FPM worker processes spawning command shells or system utilities, consistent with post-exploitation activity following a successful .pht webshell upload via CVE-2026-93352.
references:
- https://nvd.nist.gov/vuln/detail/CVE-2026-93352
- https://attack.mitre.org/techniques/T1059/004/
author: Security Arsenal
date: 2026/04/06
tags:
- attack.execution
- attack.t1059.004
- attack.t1505.003
logsource:
category: process_creation
product: linux
detection:
selection_parent:
ParentImage|endswith:
- '/apache2'
- '/httpd'
- '/php-fpm'
- '/php-fpm8.3'
- '/php-fpm8.2'
- '/php-fpm8.1'
selection_child:
Image|endswith:
- '/sh'
- '/bash'
- '/dash'
- '/curl'
- '/wget'
- '/nc'
- '/ncat'
- '/python'
- '/python3'
- '/perl'
condition: selection_parent and selection_child
falsepositives:
- Rare; some legacy admin panels or media-processing pipelines shell out from PHP — validate against application change records
level: high
KQL — Microsoft Sentinel / Defender
This query assumes Linux web server telemetry reaches Sentinel via Syslog/CEF ingestion (auditd file events) or via Defender for Endpoint onboarded Linux hosts. It hunts both the .pht artifact and web-server-spawned shell execution.
// Hunt 1: .pht file creation in web-accessible paths (MDE-onboarded Linux hosts)
DeviceFileEvents
| where TimeGenerated > ago(14d)
| where FileName endswith ".pht"
| where FolderPath has_any ("/var/www", "/storage/app", "/public/uploads", "/public/storage", "/uploads", "/media")
| project TimeGenerated, DeviceName, FolderPath, FileName, InitiatingProcessFileName, InitiatingProcessCommandLine, SHA256
| order by TimeGenerated desc;
// Hunt 2: Web server or PHP-FPM spawning shells / download tools (webshell post-exploitation)
DeviceProcessEvents
| where TimeGenerated > ago(14d)
| where InitiatingProcessFileName has_any ("apache2", "httpd", "php-fpm")
| where FileName has_any ("sh", "bash", "dash", "curl", "wget", "nc", "ncat", "python", "python3", "perl")
| project TimeGenerated, DeviceName, InitiatingProcessFileName, FileName, ProcessCommandLine, AccountName
| order by TimeGenerated desc;
// Hunt 3: Syslog/auditd file-creation telemetry via CEF/Syslog ingestion
Syslog
| where TimeGenerated > ago(14d)
| where SyslogMessage has ".pht"
| where SyslogMessage has_any ("/var/www", "storage/app", "uploads", "media")
| project TimeGenerated, Computer, ProcessName, SyslogMessage
| order by TimeGenerated desc
Velociraptor VQL
Use this artifact to sweep Linux web servers for dropped .pht payloads and enumerate recent writes under upload paths — useful both for proactive hunting and for retroactive scoping after patching.
-- Hunt for .pht webshell artifacts in web-accessible upload directories (CVE-2026-93352)
SELECT FullPath, Size, Mtime, Ctime,
hash(path=FullPath) AS FileHash
FROM glob(globs=[
'/var/www/**/*.pht',
'/var/www/**/storage/**/*.pht',
'/var/www/**/uploads/**/*.pht',
'/var/www/**/public/**/*.pht',
'/srv/www/**/*.pht',
'/home/*/public_html/**/*.pht'
])
ORDER BY Mtime DESC
-- Identify files recently written by the web server user in upload paths (possible dropped payloads)
SELECT FullPath, Size, Mtime,
stat(path=FullPath).Uid AS Uid
FROM glob(globs=['/var/www/**/uploads/**', '/var/www/**/storage/app/**'])
WHERE Mtime > now() - 1209600
AND FullPath =~ '\\.(pht|phar|php[0-9]?|phtml)$'
ORDER BY Mtime DESC
Remediation / Verification Script (Bash)
Run this on Debian/Ubuntu Apache hosts serving Laravel applications. It inventories the installed Laravel-Mediable version, sweeps for existing .pht payloads, and applies the platform-level hardening that removes .pht execution independent of the application patch.
#!/usr/bin/env bash
# CVE-2026-93352 - Laravel-Mediable .pht upload bypass verification and hardening
set -euo pipefail
APP_ROOT="${1:-/var/www}"
echo "=== [1] Identify installed Laravel-Mediable versions ==="
find "$APP_ROOT" -maxdepth 4 -name composer.lock 2>/dev/null | while read -r lock; do
ver=$(grep -A2 '"name": "plank/laravel-mediable"' "$lock" 2>/dev/null | grep '"version"' | head -1 || true)
[ -n "$ver" ] && echo " $lock -> $ver"
done
echo "=== [2] Sweep for existing .pht files (potential webshells) ==="
find "$APP_ROOT" /srv/www /home/*/public_html -type f -name '*.pht' -printf '%TY-%Tm-%Td %TH:%TM %p\n' 2>/dev/null | sort -r | head -50 || echo " none found"
echo "=== [3] Check Apache config for .pht in PHP FilesMatch handler ==="
grep -RniE 'FilesMatch.*\.pht|SetHandler.*php|AddHandler.*\.pht' /etc/apache2/ 2>/dev/null || echo " no explicit .pht handler found in /etc/apache2 (check php module defaults)"
echo "=== [4] HARDEN: strip .pht (and other dangerous variants) from PHP execution ==="
cat > /etc/apache2/conf-available/disable-pht-execution.conf <<'EOF'
# CVE-2026-93352 hardening: never execute .pht as PHP
<FilesMatch "\.pht$">
Require all denied
</FilesMatch>
# Belt-and-suspenders: deny script execution in upload/storage trees
<DirectoryMatch "/var/www/.*/(uploads|storage/app|public/storage)">
<FilesMatch "\.(php|pht|phtml|phar|php[0-9])$">
Require all denied
</FilesMatch>
</DirectoryMatch>
EOF
a2enconf disable-pht-execution
apache2ctl configtest && systemctl reload apache2 && echo " Apache hardened and reloaded"
echo "=== [5] Update Laravel-Mediable (run as the deploy user, per app) ==="
echo " cd <app_root> && composer require plank/laravel-mediable:^7.0.2 && composer update plank/laravel-mediable"
echo " Verify: grep -A2 'plank/laravel-mediable' composer.lock | grep version"
echo "=== [6] Verify blocklist now includes pht ==="
find "$APP_ROOT" -path '*/config/mediable.php' 2>/dev/null | while read -r cfg; do
echo " --- $cfg ---"
grep -n 'forbidden_extensions' -A15 "$cfg" | grep -E "'pht'" && echo " OK: pht present" || echo " WARNING: pht MISSING from forbidden_extensions"
done
Remediation
1. Patch immediately. Upgrade Laravel-Mediable to 7.0.2 or later across every application that depends on it. Do not forget transitive usage — audit every composer.lock in your estate, including staging and forgotten legacy properties, which are disproportionately represented in breach postmortems:
find /var/www -name composer.lock -exec grep -l 'plank/laravel-mediable' {} \;
cd /path/to/app && composer require plank/laravel-mediable:^7.0.2
2. Apply the platform-level fix regardless of patch status. The Apache configuration hardening in the script above — denying execution of .pht and denying any PHP execution inside upload/storage directories — is the control that survives the next incomplete blocklist. Upload directories should be byte-storage, never execution contexts. This is the single most durable mitigation in this post.
3. Serve uploads from a non-executing path. Where architecture permits, move media delivery behind a controller that streams bytes with a safe Content-Type and Content-Disposition: attachment, or offload to object storage (S3-compatible) with a separate domain. An uploaded file that is never touched by the web server's PHP handler cannot become a webshell.
4. Retroactive scoping. After patching, assume prior exposure. Sweep for .pht files (script step 2 and the VQL artifact above), review web access logs for HTTP requests to .pht URLs (grep -E '\.pht' /var/log/apache2/*access*.log), and check for www-data-owned processes, unexpected crontab entries for the web user, and new files in writable directories modified in the exposure window. Any confirmed .pht execution should be treated as a full compromise: rotate .env credentials, database passwords, and application keys.
5. Longer-term control: prefer allowlists over blocklists for upload validation — enumerate the extensions you intend to accept (e.g., jpg, png, pdf) and reject everything else. CVE-2026-93352 exists precisely because blocklist maintenance is a losing game against platform defaults that vary by distribution and change over time.
6. Monitor for KEV inclusion and vendor updates. Track the NVD entry for CVE-2026-93352 and the Laravel-Mediable repository for the 7.0.2 advisory. If CISA adds this to the Known Exploited Vulnerabilities catalog, federal civilian agencies will face a binding remediation deadline — and your SLA should move accordingly regardless of sector.
The Bigger Lesson
This is the second CVE in this codebase for the same bug in a matter of weeks: the fix for CVE-2026-49972 was bypassed by a three-letter extension the authors didn't enumerate. When you patch CVE-2026-93352, don't close the ticket at composer update. Close it when the platform can no longer execute anything an attacker uploads — because CVE-2026-93352's successor will target whatever extension the 7.0.2 blocklist forgot next.
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.