This release contains the security audit fixes, plus dependency updates including two CommonMark CVEs. All seven confirmed vulnerabilities and the multi-form CSRF regression are resolved.
🔒 Security Fixes
- PHP Code Injection in the Index Page Config Writer (Critical, CWE-94):
act_structure.phpwroteacat_permit,acat_cntpartandacat_timeoutunescaped intoinclude/config/conf.indexpage.inc.php, a file required on every frontend request. A crafted value produced persistent remote code execution triggered by any anonymous visitor. All three values are now escaped withsanitize_quote_backslash(). - Path Traversal / Local File Inclusion in Content Template Fields (High, CWE-22/CWE-73/CWE-98): Template and file name fields of content parts accepted
../sequences and absolute paths, andinclude_ext_php()skipped itsrealpath()containment check whenever the caller passed a truthy flag — whichcnt21.article.inc.phpdid. Local containment is now unconditional; the new helperssanitize_template_name()(Unicode-safe, so existing umlaut template names keep working) andpath_is_within()are applied to all template/file name fields and thecnt51GET sinks. - Stored XSS in the Backend Guestbook via Spoofable Client-IP Header (High, CWE-79/CWE-113):
getRemoteIP()trustedHTTP_CLIENT_IPandHTTP_X_FORWARDED_FORwithout validation, so an unauthenticated guestbook post could store markup that executed in the moderation view. IP values are now validated withfilter_var(FILTER_VALIDATE_IP)— a publicREMOTE_ADDRis authoritative, forwarded headers count only behind a private or reserved peer — and the output is escaped and URL-encoded. - SQL Injection in the Structure Category INSERT (Medium, CWE-89):
acat_permitandacat_cachewere interpolated intophpwcms_articlecatwithout escaping while neighbouring values used_dbEscape(). Both are escaped now, and the group/content-part ID arrays are validated as integers. - Multi-Form CSRF Token Regression (High, regression from 1.12.0): Every form on a backend page shared the session key
csrf_form_tokenand each form regenerated it, so only the last form of a page could be submitted — creating or editing backend users was impossible. The token is now generated once and reused for all forms. Refs #381. - Session Fixation (Medium, CWE-384):
login.phpdid not regenerate the session ID on successful authentication andsession.use_strict_modestayed at PHP's default. The session ID is now regenerated at the auth boundary and strict mode is enabled. - Unauthenticated Password Reminder for Inactive Accounts (Medium, CWE-620): The public password reminder form matched accounts without checking their active state. Both lookups now require an active account.
- Object Injection Candidates (Low, CWE-502): Three
unserialize()calls omitted['allowed_classes' => false]— fixed incnt14,cnt50and the shop frontend search.
📦 Dependency Updates
- league/commonmark 2.8.3 → 2.10.3: Fixes CVE-2026-71488 (quadratic-time DoS when parsing crafted Markdown) and CVE-2026-71478 (AttributesExtension unsafe-link filter bypass).
- enshrined/svg-sanitize 0.22.0 → 1.0.0: SVG upload sanitizer major upgrade, API used by
class.svg-reader.phpunchanged. - js-cookie 2.2.1 → 3.0.8, phpstan 2.2.16, phpspreadsheet 5.10.0, tinymce 8.9.2, htmlpurifier 4.19.1, idna-convert 4.2.2, symfony polyfills v1.43.0 and further updates within existing constraints.
composer auditreports no advisories.
⚙️ Changelog Comparison
For a line-by-line code view of all changes:
Comparing v1.12.3...v1.12.4