CVE-2026-48908 — SP Page Builder for Joomla: Unauthenticated File Upload → RCE
asset.uploadCustomIcon drops a PHP web shell into the web root → OS command execution & hidden Super Admin. Linux web-server telemetry hunt.Executive Summary
CVE-2026-48908 is a maximum-severity (CVSS 4.0 = 10.0) unauthenticated arbitrary-file-upload vulnerability in the SP Page Builder extension for Joomla, one of the most widely deployed Joomla page-builders. The component's asset.uploadCustomIcon controller accepts a file with no authentication and no file-type validation, so any remote attacker can upload a PHP web shell into a web-served directory and execute it — full remote code execution as the web-server user. All versions up to and including 6.6.1 are affected; the fix is 6.6.2 (released 2026-06-14), which gates the controller behind an authenticated session, a permission check, and a CSRF token.
The flaw has been exploited in the wild as a zero-day and was added to the CISA KEV catalog on 2026-07-07 (federal remediation due 2026-07-10). Observed exploitation is automated: a bot POSTs to index.php?option=com_sppagebuilder&task=asset.uploadCustomIcon (HTTP 200), then GETs the planted PHP file, then a brand-new Joomla Super Administrator account appears on the site. Some campaigns upload ZIP archives containing PHP web shells into /media/com_sppagebuilder/assets/iconfont/, and drop persistent PHP file-manager backdoors under /media/com_sppagebuilder/assets/.
Because initial access is a web request, the highest-value endpoint signal is the web server / PHP-FPM process spawning a shell or recon binary — the moment the web shell runs an OS command. The upload itself is best caught in web-server access logs (the uploadCustomIcon → GET-.php sequence) and by the tell-tale hidden admin whose email ends in @secure.local.
Defender priority: Inventory every Joomla site running SP Page Builder and confirm it is on 6.6.2+ today. Then hunt for (1) httpd/php-fpm spawning sh/bash/id/curl (§8 Q1), (2) new files under /media/com_sppagebuilder/assets/, and (3) any Joomla Super Admin with an @secure.local email. Treat a pre-6.6.2, internet-facing instance as presumed-compromised.
Source Review & Web Hunter Notes
| Tier | Source | Key Finding | Carry Fwd |
|---|---|---|---|
| 1 · Primary | NVD — CVE-2026-48908 | CVSS 10.0, affected ≤ 6.6.1, unrestricted file upload → RCE. | Yes |
| 1 · Primary | CISA KEV (added 2026-07-07) | Confirms active exploitation; FCEB due 2026-07-10. | Yes |
| 1 · Primary | Censys advisory (2026-06-24) · IONIX | Endpoint asset.uploadCustomIcon, exposure scale, exploitation detail. | Yes |
| 2 · Corrob. | mySites.guru — "SP Page Builder Zero Day RCE Fixed in 6.6.2" | Attack sequence (POST 200 → GET .php → new Super User), webshell paths, @secure.local admin, 6.6.2 fix (2026-06-14). | Yes |
| 2 · Corrob. | The Hacker News — CISA KEV additions (2026-07-08) | KEV context alongside ColdFusion/Joomla/Langflow adds. | Partial |
| 3 · Context | JoomShaper forum threads | Vendor discussion; a report that IconsTrait.php handling still warranted review post-6.6.2 — validate you are fully patched. | Partial |
Provenance note: IOCs here are structural/behavioral (endpoint path, controller task, webshell directories, @secure.local admin email) and are well-corroborated across the vendor advisory and multiple analyses. No reliable attacker C2 IP set is published as of 2026-07-12 — this pack is detection-by-behavior, not IP blocklist.
Hunt Brief & Attack Chain
Hunt hypotheses (ordered by fidelity)
- H1 (high): A web-server or PHP-FPM process spawns a shell or recon/download binary (
sh,bash,id,whoami,uname,curl,wget) — a PHP web shell executing OS commands post-upload. - H2 (med): A ZIP archive or new file is written under
/media/com_sppagebuilder/assets/(esp.iconfont/) — the web-shell delivery artifact. - H3 (med): The web-server process makes outbound network connections (reverse shell or second-stage fetch) to an external host.
- H4 (med): The web-server process spawns an interactive reverse-shell one-liner (
bash -i,python … pty.spawn,perl … Socket,nc -e). - H5 (high, native): A new Joomla Super Administrator account exists whose email ends in
@secure.local, or web-access logs showtask=asset.uploadCustomIcon(200) followed by a GET to a new.phpunder the media path.
Attack chain
| # | Step | Telemetry | Hunt angle |
|---|---|---|---|
| 1 | Unauth POST to asset.uploadCustomIcon uploads PHP/ZIP web shell | Web access log · ZipFileWritten | Log signature + file write under media path (§7, Q2) |
| 2 | GET the planted PHP file → OS command execution | Web access log · ProcessRollup2 | Web server → shell child (Q1) |
| 3 | Recon / download second stage (id, uname, curl) | ProcessRollup2 · NetworkConnectIP4 | Recon binaries + egress under web parent (Q1, Q3) |
| 4 | Reverse shell / interactive access | ProcessRollup2 · NetworkConnectIP4 | Reverse-shell one-liners (Q4) |
| 5 | Create hidden Joomla Super Admin (@secure.local) | Joomla DB / app audit | Rogue admin review (§7, native) |
| 6 | Drop persistent PHP file-manager backdoor | File write under media path | New .php under /media/com_sppagebuilder/assets/ (§7) |
Consolidated IOC Table
| Type | Value | Conf | Action | Context |
|---|---|---|---|---|
| URL / controller | index.php?option=com_sppagebuilder&task=asset.uploadCustomIcon | high | hunt | Exploited upload endpoint — POST returning 200 from unauthenticated source |
| Path | /media/com_sppagebuilder/assets/iconfont/ | high | hunt | Web-shell / ZIP drop location |
| Path | /media/com_sppagebuilder/assets/ | high | hunt | Persistent PHP file-manager backdoor location |
| Account artifact | Joomla Super Admin email ending @secure.local | high | hunt | Hidden admin created post-exploit; domain never used legitimately |
| Behavior | Web server / php-fpm → shell/recon child | high | detect | Web-shell command execution (Q1) |
| Behavior | Access-log: POST uploadCustomIcon (200) → GET new .php | high | hunt | Exploitation sequence in web logs (§7) |
| Version | SP Page Builder ≤ 6.6.1 | high | detect | Vulnerable; patch to 6.6.2+ |
Affected Surface & Telemetry Matrix
| Surface | Required telemetry | Priority | Gap risk |
|---|---|---|---|
| Joomla web servers running SP Page Builder ≤ 6.6.1 | Falcon Linux sensor · ProcessRollup2 · NetworkConnectIP4 | Critical | Shared-hosting / unmanaged CMS boxes often lack a sensor |
| Web root / media upload directories | File-write telemetry (ZipFileWritten) · web access logs | High | Arbitrary PHP writes may not raise a PE/ELF write event — pair with access logs |
| Joomla application / user store | Joomla admin audit · DB review | High | Rogue Super Admin invisible to endpoint telemetry |
| Reverse proxy / WAF / CDN in front of Joomla | Proxy/WAF logs | Medium | Upload POST may be observable at the edge before the origin |
ATT&CK Mapping
| Tactic | Technique | Observed behavior | Query / Control |
|---|---|---|---|
| Initial Access | T1190 · Exploit Public-Facing Application | Unauth asset.uploadCustomIcon file upload | §7 log hunt · patch |
| Persistence | T1505.003 · Web Shell | PHP web shell / file-manager backdoor under media path | Q2 · §7 |
| Execution | T1059.004 · Unix Shell | Web shell runs OS commands | Q1 |
| Discovery | T1082 · System Info Discovery | id/uname/whoami under web parent | Q1 |
| Command & Control | T1071 · App-Layer Protocol · T1059 reverse shell | Web-server egress / reverse-shell one-liner | Q3, Q4 |
| Persistence / Priv-Esc | T1136.001 · Create Account · T1078 valid accounts | Hidden Joomla Super Admin (@secure.local) | §7 native |
| Ingress Tool Transfer | T1105 | curl/wget second-stage fetch by web process | Q1, Q3 |
Native Audit-Log Hunts (non-CQL)
- Version audit (do first): Confirm SP Page Builder is 6.6.2 or newer on every Joomla site. In the Joomla admin: Extensions → Manage → filter "Page Builder", or check
administrator/components/com_sppagebuilder/sppagebuilder.xmlfor the<version>string. - Web access-log signature: Search access logs for
task=asset.uploadCustomIconwith aPOSTand200, especially from unauthenticated sources, followed shortly by aGETto a.phpunder/media/com_sppagebuilder/. That POST→GET pair is the exploitation fingerprint. - Web-shell file sweep: On the web root, list any
.phpunder/media/com_sppagebuilder/assets/(andiconfont/) — this tree should contain fonts/icons, never PHP. Also look for recently-modified ZIP archives there. - Rogue admin review: In Joomla Users, flag any Super User with an email ending
@secure.localor any admin account created around the exploitation window. Verify against your change record. - Integrity: Diff the Joomla install against a known-good baseline; review
configuration.phpexposure and recently-changed files across the web root.
CrowdStrike LogScale CQL Hunt Queries
Looks for: a web-server or PHP-FPM process becoming the parent of a shell or host-recon/download binary — a PHP web shell running OS commands after the uploadCustomIcon drop. FP: low; well-behaved PHP apps rarely shell out to id/uname. Baseline any plugin that legitimately calls system utilities.
// HUNT: Joomla/PHP web server spawning shell or recon binary (web-shell RCE) // MITRE: T1190, T1505.003, T1059.004, T1082 // CONF: high FP: low COST: low | REQUIRES: Linux sensor ProcessRollup2 #event_simpleName=/ProcessRollup2|SyntheticProcessRollup2/ | ParentBaseFileName=/^(httpd|apache2|nginx|php-fpm[0-9.]*|php-cgi|php[0-9.]*|litespeed|lsphp)$/i | FileName=/^(sh|bash|dash|id|uname|whoami|hostname|curl|wget|nc|ncat|python3?|perl)$/i | table([ComputerName, aid, UserName, ParentBaseFileName, FileName, CommandLine], limit=200)
Looks for: a ZIP archive written under /media/com_sppagebuilder/assets/ — the observed web-shell delivery artifact. FP: low; this tree holds icon fonts, not uploaded archives. Note: a bare .php write may not raise a file-write event — pair with the native file sweep (§7) and Q1.
// HUNT: archive dropped under com_sppagebuilder assets (web-shell delivery) // MITRE: T1505.003, T1105 // CONF: high FP: low COST: low | REQUIRES: Linux sensor ZipFileWritten #event_simpleName=/ZipFileWritten/ | TargetFileName=/com_sppagebuilder\/assets/i | table([ComputerName, aid, UserName, TargetFileName], limit=200)
Looks for: outbound connections initiated directly by a web-server/PHP process — a reverse shell or second-stage tool fetch from the web shell. FP: medium — apps legitimately call external APIs. TUNING: exclude known outbound API/update destinations and scope to non-standard ports; correlate with Q1/Q4 hits on the same aid.
// HUNT: web-server/php process initiating outbound network connections // MITRE: T1071, T1105 // CONF: medium FP: medium COST: low | REQUIRES: Linux sensor NetworkConnectIP4 // TUNING: exclude sanctioned API/update egress; focus on non-standard ports + Q1/Q4 correlation #event_simpleName=/NetworkConnectIP4/ | ContextBaseFileName=/^(httpd|apache2|nginx|php-fpm[0-9.]*|php-cgi|php[0-9.]*|lsphp)$/i | table([ComputerName, aid, ContextBaseFileName, RemoteAddressIP4, RemotePort], limit=200)
Looks for: classic reverse-shell command-line patterns spawned under a web server — bash -i to /dev/tcp, a Python pty.spawn, a Perl Socket shell, or nc -e. FP: low; these strings under a web parent are almost never benign.
// HUNT: reverse-shell one-liner spawned by a web server (post web-shell) // MITRE: T1059.004, T1071 // CONF: high FP: low COST: low | REQUIRES: Linux sensor ProcessRollup2 #event_simpleName=/ProcessRollup2|SyntheticProcessRollup2/ | ParentBaseFileName=/^(httpd|apache2|nginx|php-fpm[0-9.]*|php-cgi|php[0-9.]*|lsphp|sh|bash)$/i | CommandLine=/(bash\s+-i|\/dev\/tcp\/|pty\.spawn|Socket\;.*exec|\bnc\s+-e|mkfifo)/i | table([ComputerName, aid, UserName, ParentBaseFileName, FileName, CommandLine], limit=200)
CrowdStrike Custom IOA Recommendations
| IOA name | Pattern | Exclusions | Deploy |
|---|---|---|---|
| Joomla-WebShell-Exec | Parent = httpd/nginx/php-fpm, Child = shell or recon binary (Q1) | Baselined plugins that call system utilities | Linux process IOA · Detect→Prevent after baseline |
| WebSvc-ReverseShell | Web parent + reverse-shell command line (Q4) | None expected | Linux process IOA · Detect→Prevent (high-signal) |
| SPPB-Media-Archive-Drop | ZIP written under com_sppagebuilder/assets (Q2) | Legitimate extension-update tooling writing to media | Linux file IOA · Detect |
Q1 and Q4 are portable web-shell detections — they generalize beyond this CVE to any PHP-app RCE, so promoting them hardens you against the next Joomla/WordPress upload bug too.
Machine-Readable IOC Appendix
type,value,action,severity,expiration,description,tags sha256,REPLACE_WITH_WEBSHELL_SHA256,prevent,critical,2027-01-12,SP Page Builder web shell,cve:CVE-2026-48908 ipv4,REPLACE_WITH_ATTACKER_IP,detect,high,2026-10-12,CVE-2026-48908 exploit source (from your logs),cve:CVE-2026-48908
# httpd/nginx/php-fpm -> shell/recon child (web-shell command exec) # ZIP or .php written under /media/com_sppagebuilder/assets/(iconfont/) # Reverse-shell one-liner (bash -i /dev/tcp, python pty.spawn, nc -e) under web parent # Web parent making outbound connections to external host
# Access log: POST index.php?option=com_sppagebuilder&task=asset.uploadCustomIcon => 200 # then GET /media/com_sppagebuilder/assets/**/*.php # Joomla Super Admin with email ending @secure.local # New/modified .php or .zip under /media/com_sppagebuilder/assets/
# SP Page Builder >= 6.6.2 (fix released 2026-06-14) # Deny PHP execution in /media and /images (web-server config) # Web-app user cannot write into web-served code dirs # WAF rule: block unauth POST to task=asset.uploadCustomIcon
No reliable attacker C2 IP set is published — the CSV uses REPLACE_WITH_… placeholders you fill from your own access logs after identifying the exploit source. The durable detections are behavioral (above).
Detection Validation Gates
- Telemetry ready: Confirm a Falcon Linux sensor is on every Joomla web host. Shared/managed hosting may not permit a sensor — fall back to web-log hunts (§7).
- Benign baseline: Run Q1 and Q3 in monitor for 3–7 days; catalog any plugin that legitimately shells out or calls external APIs before promoting to Prevent.
- Positive test: In a lab, drop a benign PHP page that runs
idand request it — confirm Q1 fires. Write a test ZIP under the media path — confirm Q2 fires. - Promotion: Q1 and Q4 are strong Prevent candidates after baseline. Q2 → Detect. Q3 stays Detect/hunt (correlate with Q1/Q4).
Hardening — Tiered
- Patch to SP Page Builder 6.6.2+ — the fix (2026-06-14) gates
uploadCustomIconbehind auth, permission, and CSRF. This closes the vulnerability. (M1051 · vendor advisory) - Deny PHP execution in upload dirs — block
.phphandling in/mediaand/imagesat the web server so an uploaded shell can't run even if written. (M1050 · CIS Apache/NGINX Benchmark) - WAF virtual patch — block unauthenticated
POSTtotask=asset.uploadCustomIconand uploads of non-image content-types to the component. (M1050)
- Least-privilege web root — the web-app user should not have write access to web-served code/media where it can plant executable content; separate upload storage from the exec path. (M1022 · CIS)
- Egress control — restrict outbound connections from web servers to explicit allowlists; this breaks reverse shells and second-stage fetches. (M1037)
- Rogue-admin sweep & MFA — remove any
@secure.local/ unexpected Super Admin, rotate admin credentials, and enforce MFA on Joomla admin. (M1032, M1018)
- File-integrity monitoring on the web root to alert on any new
.phpin media/upload trees. (M1022) - CMS & extension patch program — inventory all Joomla extensions and drive a defined SLA for security updates; page-builders are a recurring RCE surface. (M1051)
- Reverse proxy + hardened perimeter — terminate Joomla behind a proxy/WAF with upload inspection and rate-limiting. (M1030, M1050)
Deployable Playbooks
1 · Find vulnerable version + web shells (Linux, run per web host)
# SP Page Builder version grep -Ri '<version>' \ /var/www/*/administrator/components/com_sppagebuilder/sppagebuilder.xml 2>/dev/null # Any PHP (or ZIP) under the media assets tree = suspicious find /var/www -path '*com_sppagebuilder/assets*' \( -name '*.php' -o -name '*.zip' \) \ -printf '%TY-%Tm-%Td %p\n' 2>/dev/null
2 · Access-log signature sweep
# POST to the vulnerable controller returning 200 grep -E 'task=asset\.uploadCustomIcon' /var/log/apache2/*access* /var/log/nginx/*access* 2>/dev/null \ | grep -E 'POST' | grep -E ' 200 ' # Follow-on GETs to planted php under the media path grep -E 'GET .*com_sppagebuilder/assets/.*\.php' /var/log/apache2/*access* /var/log/nginx/*access* 2>/dev/null
3 · Block PHP execution in upload dirs (Apache example)
# In the vhost / .htaccess for /media and /images:
<Directory /var/www/html/media>
<FilesMatch "\.(php|phtml|php[0-9]|phar)$">
Require all denied
</FilesMatch>
</Directory>
# NGINX equivalent: location ~* /(media|images)/.*\.php$ { return 403; }
Containment Runbook
| Phase | Actions | Owner | Evidence |
|---|---|---|---|
| Isolate | Network-contain any web host with Q1/Q4 hits or a confirmed web shell (Falcon RTR). Put a WAF block on the vulnerable controller. | SOC / IR | Falcon detections, access-log POST 200 |
| Eradicate | Remove web shells / ZIPs from /media/com_sppagebuilder/assets/; delete rogue @secure.local Super Admin; patch to 6.6.2+. | IR / Web team | File-sweep output, Joomla user list |
| Recover | Restore any modified core files from a known-good backup; re-verify plugin integrity; re-enable the site behind the WAF virtual patch. | Web team | Integrity diff, restore log |
| Rotate | Rotate Joomla admin passwords, secret/session keys in configuration.php, and any DB creds the web shell could read. | Web team / IAM | Rotation ticket |
| Report | Preserve web shells & logs for IR; notify per policy; confirm no downstream data access. | IR Lead | Evidence bundle, timeline |
Detection Coverage Map
| Technique | Behavior | CQL | IOA | Coverage |
|---|---|---|---|---|
| T1190 · Public-facing exploit | uploadCustomIcon upload | native §7 | No | Partial |
| T1505.003 · Web shell | ZIP/PHP under media path | Q2 | Yes | Partial |
| T1059.004 · Unix shell | web server → shell | Q1 | Yes | Good |
| T1082 · Discovery | id/uname under web parent | Q1 | Yes | Good |
| T1071 · C2 / reverse shell | egress + reverse-shell one-liner | Q3, Q4 | Yes | Good |
| T1136.001 · Create account | hidden @secure.local admin | native §7 | No | GAP |
Known gaps: The initial upload (T1190) and the hidden Joomla Super Admin (T1136.001) are application-layer events not visible to endpoint process telemetry — cover them with the web-access-log and Joomla-user audits in §7. A bare .php web-shell write may not raise a file-write event; Q2 catches the ZIP-delivery variant, and §7 covers direct PHP drops. Managed/shared hosting without a Falcon sensor is the largest gap — rely on §7 there. Validation gates (§11) must pass before promoting Q1/Q4 to Prevent.
Hunt Summary Ticket
TITLE: CVE-2026-48908 — SP Page Builder Unauth File Upload -> RCE SEVERITY: Critical (CVSS 10.0, exploited in the wild, KEV 2026-07-07) SCOPE: Joomla web servers running SP Page Builder <= 6.6.1 (Linux) HYPOTHESIS: Unauth uploadCustomIcon -> PHP web shell -> OS exec / reverse shell / hidden Super Admin QUERIES: Q1 web-svc->shell (HIGH) | Q2 ZIP under media path | Q3 web egress | Q4 reverse shell (HIGH) DO FIRST: Confirm SP Page Builder >= 6.6.2; run Q1 + access-log sweep (§7) FINDINGS: <fill after hunt> GAPS: Upload event + hidden admin (app-layer/native only); bare .php write; sensorless hosting ACTIONS: Patch 6.6.2+; deny PHP exec in /media; WAF-block uploadCustomIcon; remove @secure.local admin OWNER: HuntPack VERSION: v0.2 · 2026-07-12
Changelog
table() calls now carry an explicit row limit: the default is 200 and truncation is silent, so a capped result was indistinguishable from a complete one. Atomic-IOC sweeps (filters over 5+ hashes or C2 IPs) use limit=max so a wide infection is never silently under-scoped; behavioural hunts use limit=200, where exceeding the cap indicates the query needs tuning. Where present, event names that do not exist in the Falcon data model were corrected (e.g. ServiceInstalled is a Sysmon concept, not a Falcon event; ElfFileWritten is ELFFileWritten) — such queries could never return a row. No detection logic, fields, or IOCs changed.References
| Tier | Source | Used for | Accessed |
|---|---|---|---|
| 1 | NVD — CVE-2026-48908 | CVSS, affected versions, vuln class | 2026-07-12 |
| 1 | CISA KEV Catalog (added 2026-07-07) | Active-exploitation confirmation, remediation date | 2026-07-12 |
| 1 | Censys advisory — CVE-2026-48908 (2026-06-24) | Endpoint, exposure, exploitation detail | 2026-07-12 |
| 2 | mySites.guru — SP Page Builder Zero Day RCE (6.6.2) | Attack sequence, webshell paths, @secure.local admin, fix version/date | 2026-07-12 |
| 2 | The Hacker News — CISA KEV additions (2026-07-08) | KEV context | 2026-07-12 |
| 3 | IONIX threat center — CVE-2026-48908 | Corroborating technical summary | 2026-07-12 |