It's like leaving a colour-printer that also prints keys in the lobby, unlocked, signature pad and all
CVE-2026-102785 is an unauthenticated remote code execution flaw in YOOtheme Pro's publicly accessible image transformation handler, affecting every 5.x build from 5.0.0 through 5.0.52 on both Joomla and WordPress editions. The handler accepts image-processing requests validated by a URL signature, but in vulnerable versions the signature does not cover *which* operations run or *where* the result is written. An attacker grabs a valid signature from any <img> tag on the public site, injects extra image operations plus a path-traversal payload, and causes the handler to write a PNG/PHP polyglot into an executable public media directory. One HTTP request, zero authentication, full code execution as the web-server user. The fix in 5.0.53 restricts operations to a hardcoded allowlist and validates the cache filename against the signed URL before any write.
The Joomla assigner scored this CVSS 4.0 10.0 Critical, and for once the top-of-scale rating is warranted. Every precondition the attacker needs — network reachability, a valid signature, a writable executable directory — is *the default state* of every YOOtheme Pro 5.x site. There is no authentication gate, no privilege escalation chain, no user-interaction requirement, and the polyglot-upload technique is thoroughly documented. The only slight attenuation is that some hardened deployments disable PHP execution in media directories via .htaccess or Nginx location blocks, but this is the exception, not the norm, in the Joomla/WordPress ecosystem. With ~150,000 licensed customers and the product powering both Joomla and WordPress sites, the reachable attack surface is meaningful.
4 steps from start to impact.
Harvest a valid image signature
<img> tag whose src points to the YOOtheme Pro image handler leaks a valid HMAC signature. No scanning or fuzzing is required — the signature is disclosed by design on every page that uses image transformations. Tools: curl, browser dev-tools.- Target site runs YOOtheme Pro 5.0.0–5.0.52
- At least one page uses the image transformation handler (virtually all do)
- None — the signature is served to every anonymous visitor
Inject malicious image operations + path traversal
../ sequences to traverse out of the cache directory into an executable public path (e.g., /media/ on Joomla, /wp-content/uploads/ on WordPress). The handler accepts the request because the base signature is valid. Tools: curl, python-requests, custom HTTP client.- Valid signature from Step 1
- Image handler does not validate operation list or output path against the signature (vulnerable behavior in ≤5.0.52)
- If the web-application firewall has a rule blocking
../in the specific parameter — uncommon for image endpoints
../) in image handler query parameters. ModSecurity CRS rule 930110 (path traversal) could catch this if the image handler endpoint is not whitelisted.Write PNG/PHP polyglot to executable directory
.php extension (or when the media directory processes .phtml/.php extensions by default). The result is a persistent webshell placed in a publicly browsable directory. Tools: ImageMagick/GD polyglot generators, well-documented technique.- Web server executes PHP files in the target media directory (default for Joomla/WordPress)
- No filesystem-level write restriction (chroot, SELinux, read-only mounts) blocking the write
- Hardened deployments with
php_flag engine offordeny *.phpin media directory .htaccess - Nginx configs that restrict PHP execution to specific location blocks
- SELinux or AppArmor profiles that block writes outside the cache directory
.php or .phtml files in media directories. Endpoint agents can alert on unusual file creation by the web-server process.Execute webshell for full server compromise
www-data, apache, or nobody). From here, the attacker can read database credentials, exfiltrate site data, install persistent backdoors, pivot to other services on the host, or escalate privileges. Tools: curl, any C2 framework (Cobalt Strike, Sliver, Havoc).- Polyglot file is accessible via HTTP
- PHP execution is enabled for the target path
- Egress filtering may prevent reverse-shell callbacks
- Host-based EDR may detect suspicious process spawning from the web-server user
www-data or apache spawning shells, making network connections, or reading /etc/shadow. SIEM correlation on new outbound connections from web servers. Access logs will show the GET request to the polyglot file path.../ or ..%2f sequences in query parameters. This breaks Step 2 of the chain. Deploy within 3 days per noisgate mitigation SLA for CRITICAL. Example ModSecurity rule: SecRule ARGS "@contains ../" "id:100001,phase:1,deny,log,msg:'YOOtheme path traversal attempt'" scoped to the image handler URI..htaccess rules (php_flag engine off or <FilesMatch \.php$> Deny from all </FilesMatch>) to Joomla's /media/ and /cache/ directories, or equivalent Nginx location blocks. For WordPress, apply to /wp-content/uploads/. This breaks Step 3 — even if the polyglot is written, PHP won't execute. Deploy within 3 days per noisgate mitigation SLA..php, .phtml, or .phar files created after the site was built. Check for files with PNG magic bytes (\x89PNG) that also contain <?php strings. Review web-server access logs for unusual requests to the image handler with atypical query lengths or ../ patterns. Run find /path/to/webroot/media -name '*.php' -newer /path/to/webroot/index.php as a quick sweep.- CMS-level authentication hardening (MFA, strong passwords, IP restrictions on admin panels) — the image handler is a *public* endpoint, not behind the admin login. Locking down
/administrator/or/wp-admin/does not protect against this attack. - Rate limiting — the exploit requires only a single HTTP request. Rate limiting would need to be set to literally zero requests to the image handler to be effective, which would break legitimate image serving.
- Content Security Policy (CSP) headers — CSP controls what the *browser* loads, not what the *server* writes to disk. This is a server-side vulnerability; CSP is irrelevant.
- Disabling unused Joomla/WordPress plugins — YOOtheme Pro is the *theme and page builder itself*, not an optional plugin that can be disabled without replacing the entire site template.
The supporting signals.
| In-the-wild exploitation | Not confirmed. Not listed on CISA KEV as of 2026-10-22. No GreyNoise tags or mass-scanning signals observed yet. However, the vulnerability was disclosed <24 hours ago — exploitation lag is typical for CMS bugs. |
|---|---|
| Proof-of-concept availability | No public PoC on GitHub, ExploitDB, or pocindex.io as of 2026-10-22. The SecureWithUmer/CVE-2026-PoCs repository does not yet list this CVE. However, the vulnerability description in the advisory is sufficiently detailed (signature reuse + path traversal + polyglot write) that a competent attacker can reconstruct the exploit from the description alone. The PNG/PHP polyglot technique is well-documented publicly. Expect a weaponized PoC within days. |
| EPSS score | Not yet scored — CVE published 2026-10-22, EPSS typically populates within 24–72 hours. Given the unauth/RCE/network-accessible profile, expect a high EPSS score (>0.7) once scored. |
| CISA KEV status | Not listed as of 2026-10-22. Eligible for addition once in-the-wild exploitation is confirmed. |
| CVSS vector | Assigner (Joomla) published CVSS 4.0: 10.0 — CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H/E:A/AU:Y. NVD has not yet published a CVSS 3.1 vector (status: *Received*). Equivalent CVSS 3.1 estimate: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H = 9.8. |
| Affected versions | YOOtheme Pro 5.0.0 – 5.0.52 (both Joomla and WordPress editions). YOOtheme Pro 4.x and earlier are not affected. |
| Fixed version | YOOtheme Pro 5.0.53, released 2026-10-21 at 14:00 UTC. Fix restricts image operations to a hardcoded allowlist (type, crop, resize, rotate, flip, thumbnail) and validates cache filename against the signed URL. |
| Installed base & exposure | YOOtheme claims 150,000+ licensed customers. BuiltWith shows ~24,000 live sites using YOOtheme-related components. All are internet-facing by nature (CMS websites). No Shodan/Censys fingerprinting tag exists for YOOtheme Pro specifically, but Joomla and WordPress instances are broadly indexed. |
| Disclosure timeline | 2026-10-20: YOOtheme pre-announced critical update. 2026-10-21: Patch (5.0.53) released. 2026-10-22: CVE-2026-102785 published. Responsible disclosure — patch preceded public CVE by ~1 day. |
| Researcher attribution | Not publicly credited. The Joomla VEL assigned the CVE; the discovering researcher is not named in available advisories. |
Sources.
- mySites.guru — YOOtheme Pro 5.0.53 Critical RCE Fix
- db8.nl — Two Critical Security Updates: PHP and YOOtheme Pro
- Offseq Radar — CVE-2026-102785 Threat Intelligence
- Strix AI — CVE-2026-102785 Analysis
- YOOtheme Pro Changelog (5.0.53 entry)
- VulDB — CVE-2026-102785 YOOtheme Pro Image Transformation
- Medium — PNG/PHP Polyglot Upload Technique Reference
Why this verdict
- Zero-friction attack chain: Every precondition — a valid signature, a writeable executable directory, network reachability — is the *default state* of every YOOtheme Pro 5.x site. The attacker needs nothing they can't get from viewing page source. No authentication, no user interaction, no race condition.
- Signature-by-design disclosure eliminates the one theoretical gate: The image handler's HMAC signature is embedded in
<img>tags served to every anonymous visitor. This is not a leaked secret — it is part of normal site operation. The attacker harvest step has literally zero friction. - Polyglot-to-RCE is a solved problem: PNG/PHP polyglot generation is a well-documented technique with public tooling. The creative work was finding the signature-reuse + path-traversal combination — but once the advisory describes it, reproduction is straightforward.
- Role multiplier: YOOtheme Pro sites are internet-facing web servers. (a) *Low-value role:* personal blogs, hobby sites — host-level compromise, data loss limited. (b) *Typical role:* SMB business websites with customer data, e-commerce, contact forms — host compromise exposes PII, payment data, and database credentials. (c) *High-value role:* multi-tenant hosting environments where a single compromised Joomla/WordPress instance shares a server with other sites, or sites that are part of a managed hosting fleet — compromise of one site can pivot to others via shared credentials, local privilege escalation, or symlink attacks. While this component is not a canonical high-value-role product (it's a CMS extension, not an IdP or hypervisor), the blast radius on shared hosting and the universal internet exposure keep this firmly at CRITICAL.
- 150K+ installed base, all internet-facing: Unlike an internal-only service where you can argue limited exposure, every YOOtheme Pro site is reachable from the public internet. The addressable target population is the entire installed base.
Why not higher?
This is assessed at 9.6, not 10.0, because a small fraction of deployments will have hardened web-server configurations that disable PHP execution in media/upload directories (via .htaccess, Nginx location rules, or SELinux policies), which breaks Step 3 of the chain. Additionally, YOOtheme Pro is a CMS extension — not a domain controller, hypervisor, or identity provider — so the blast radius of a single compromise is host-level, not fleet-level or identity-level, unless the host is in a shared-hosting environment.
Why not lower?
Downgrading below CRITICAL is not defensible. The chain is pre-auth, single-request, zero-interaction, and targets a component that is internet-facing *by definition*. There is no prerequisite that implies prior compromise. The attacker needs nothing except the ability to view a web page. The ~150K installed base and the detailed advisory description make weaponization imminent. Any severity below CRITICAL would understate the urgency for the tens of thousands of exposed sites.
Crowdsourced verification payload.
Run this script on each web server host running YOOtheme Pro. It checks both Joomla and WordPress installations. Requires read access to the webroot (run as root or the web-server user). Usage: sudo bash check_cve_2026_102785.sh /var/www/html
#!/usr/bin/env bash
# check_cve_2026_102785.sh — Detect YOOtheme Pro versions vulnerable to CVE-2026-102785
# Usage: bash check_cve_2026_102785.sh <webroot_path>
# Exit codes: 0=PATCHED, 1=VULNERABLE, 2=UNKNOWN
set -euo pipefail
WEBROOT="${1:-}"
if [[ -z "$WEBROOT" ]]; then
echo "Usage: $0 <webroot_path>"
echo "UNKNOWN — no webroot path provided"
exit 2
fi
if [[ ! -d "$WEBROOT" ]]; then
echo "UNKNOWN — directory '$WEBROOT' does not exist"
exit 2
fi
VULN_MIN="5.0.0"
VULN_MAX="5.0.52"
FOUND=0
# Version comparison: returns 0 if $1 <= $2
version_lte() {
printf '%s\n%s' "$1" "$2" | sort -V | head -n1 | grep -qx "$1"
}
check_version() {
local ver="$1" src="$2"
if version_lte "$VULN_MIN" "$ver" && version_lte "$ver" "$VULN_MAX"; then
echo "VULNERABLE — YOOtheme Pro $ver detected ($src)"
echo " Affected range: $VULN_MIN – $VULN_MAX"
echo " Fix: Update to 5.0.53 or later"
FOUND=1
return 1
elif version_lte "$VULN_MAX" "$ver" && [[ "$ver" != "$VULN_MAX" ]]; then
echo "PATCHED — YOOtheme Pro $ver detected ($src), >= 5.0.53"
FOUND=1
return 0
else
echo "PATCHED — YOOtheme Pro $ver detected ($src), below affected range (v4.x or earlier)"
FOUND=1
return 0
fi
}
# Check Joomla installations
for xml in $(find "$WEBROOT" -path '*/templates/yootheme/templateDetails.xml' -type f 2>/dev/null); do
VER=$(grep -oPm1 '(?<=<version>)[^<]+' "$xml" 2>/dev/null || true)
if [[ -n "$VER" ]]; then
check_version "$VER" "Joomla: $xml" || true
fi
done
# Check WordPress installations
for css in $(find "$WEBROOT" -path '*/themes/yootheme/style.css' -type f 2>/dev/null); do
VER=$(grep -oPm1 'Version:\s*\K[0-9]+\.[0-9]+\.[0-9]+' "$css" 2>/dev/null || true)
if [[ -n "$VER" ]]; then
check_version "$VER" "WordPress: $css" || true
fi
done
# Check composer.json as fallback
for cj in $(find "$WEBROOT" -path '*/yootheme/composer.json' -maxdepth 5 -type f 2>/dev/null); do
VER=$(grep -oPm1 '"version"\s*:\s*"\K[0-9]+\.[0-9]+\.[0-9]+' "$cj" 2>/dev/null || true)
if [[ -n "$VER" ]]; then
check_version "$VER" "composer: $cj" || true
fi
done
if [[ $FOUND -eq 0 ]]; then
echo "UNKNOWN — no YOOtheme Pro installation found under $WEBROOT"
exit 2
fi
# Set exit code based on whether any vulnerable instance was found
grep -q '^VULNERABLE' <<< "$(bash "$0" "$WEBROOT" 2>/dev/null)" 2>/dev/null && exit 1 || exit 0