← Back to Feed CACHED · 2026-10-22 13:45:07 · CACHE_KEY CVE-2026-102785
CVE-2026-102785 · CWE-434 · Disclosed 2026-10-22

YOOtheme Pro image handler unauthenticated RCE via signature-reuse and path-traversal polyglot write

ASSESSED — NOISGATE
Vendor
—
—
—
Reassessed
—
—
—
Verdict: —
Do you agree?
01 · The Real Story

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.

"Unauth RCE via public image handler; any visitor can drop a webshell with one request."
02 · The Attack Path

4 steps from start to impact.

STEP 01

Harvest a valid image signature

The attacker views the HTML source of any public page on the target site. Every <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.
Conditions required:
  • Target site runs YOOtheme Pro 5.0.0–5.0.52
  • At least one page uses the image transformation handler (virtually all do)
Where this breaks in practice:
  • None — the signature is served to every anonymous visitor
STEP 02

Inject malicious image operations + path traversal

The attacker constructs a crafted request to the same image handler endpoint, reusing the harvested signature but appending additional image operations not covered by the HMAC. Crucially, the output destination (cache filename) is also not bound to the signature, so the attacker adds ../ 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.
Conditions required:
  • Valid signature from Step 1
  • Image handler does not validate operation list or output path against the signature (vulnerable behavior in ≤5.0.52)
Where this breaks in practice:
  • If the web-application firewall has a rule blocking ../ in the specific parameter — uncommon for image endpoints
Detection/coverage: WAF logs may show path-traversal patterns (../) in image handler query parameters. ModSecurity CRS rule 930110 (path traversal) could catch this if the image handler endpoint is not whitelisted.
STEP 03

Write PNG/PHP polyglot to executable directory

The image handler processes the injected operations and writes the resulting file to the attacker-controlled path. The file is a polyglot: valid PNG headers satisfy image-parsing logic, while embedded PHP code executes when the web server processes the .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.
Conditions required:
  • 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
Where this breaks in practice:
  • Hardened deployments with php_flag engine off or deny *.php in media directory .htaccess
  • Nginx configs that restrict PHP execution to specific location blocks
  • SELinux or AppArmor profiles that block writes outside the cache directory
Detection/coverage: File-integrity monitoring (AIDE, OSSEC, Tripwire) will flag new .php or .phtml files in media directories. Endpoint agents can alert on unusual file creation by the web-server process.
STEP 04

Execute webshell for full server compromise

The attacker requests the polyglot file via its public URL. The web server executes the embedded PHP, giving the attacker arbitrary command execution as the web-server user (typically 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).
Conditions required:
  • Polyglot file is accessible via HTTP
  • PHP execution is enabled for the target path
Where this breaks in practice:
  • Egress filtering may prevent reverse-shell callbacks
  • Host-based EDR may detect suspicious process spawning from the web-server user
Detection/coverage: EDR/HIDS alerts on 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.
03 · Compensating Control

1
CRITICAL 9.6→IGNORE 0.0
SEVERITY REDUCED
Patch to YOOtheme Pro 5.0.53 immediately — This is the definitive fix. Update via Joomla's System → Update → Extensions or WordPress's Updates screen. Per the noisgate mitigation SLA for CRITICAL, deploy within 3 days. Given that this is a pre-auth RCE with no friction, treat this as an emergency patch — same-day if possible.
2
CRITICAL 9.6→MEDIUM 5.5
SEVERITY REDUCED
Block path-traversal patterns in image handler requests via WAF — Add a WAF rule (ModSecurity, Cloudflare, AWS WAF) that blocks requests to the YOOtheme image handler endpoint containing ../ 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.
3
CRITICAL 9.6→MEDIUM 4.5
SEVERITY REDUCED
Disable PHP execution in media and cache directories — Add .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.
4
CRITICAL 9.6→CRITICAL 9.6
Audit for existing compromise indicators — Search media and cache directories for unexpected .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.
5
CRITICAL 9.6→HIGH 7.0
SEVERITY REDUCED
Place YOOtheme Pro sites behind Cloudflare or equivalent reverse proxy with managed WAF ruleset — Managed WAF rulesets from Cloudflare, AWS, or Akamai may catch the path-traversal component of this exploit even without a CVE-specific rule, because they include generic directory-traversal signatures. This adds defense-in-depth but is not a guaranteed block since the image handler endpoint may be whitelisted in some WAF profiles. Deploy within 3 days.
What doesn't work
  • 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.
04 · Intelligence Metadata

The supporting signals.

In-the-wild exploitationNot 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 availabilityNo 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 scoreNot 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 statusNot listed as of 2026-10-22. Eligible for addition once in-the-wild exploitation is confirmed.
CVSS vectorAssigner (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 versionsYOOtheme Pro 5.0.0 – 5.0.52 (both Joomla and WordPress editions). YOOtheme Pro 4.x and earlier are not affected.
Fixed versionYOOtheme 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 & exposureYOOtheme 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 timeline2026-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 attributionNot publicly credited. The Joomla VEL assigned the CVE; the discovering researcher is not named in available advisories.

Sources.

  1. mySites.guru — YOOtheme Pro 5.0.53 Critical RCE Fix
  2. db8.nl — Two Critical Security Updates: PHP and YOOtheme Pro
  3. Offseq Radar — CVE-2026-102785 Threat Intelligence
  4. Strix AI — CVE-2026-102785 Analysis
  5. YOOtheme Pro Changelog (5.0.53 entry)
  6. VulDB — CVE-2026-102785 YOOtheme Pro Image Transformation
  7. Medium — PNG/PHP Polyglot Upload Technique Reference
05 · The Call

Final Verdict
= UNCHANGED to CRITICAL (9.6/10)

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.

06 · Verification

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

noisgate-verify.sh
BASHREAD-ONLYSAFE
#!/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