{"id":"GHSA-2ff2-mx52-q8wp","summary":"October CMS: PHP Object Injection via Backend Widget Session Storage","details":"The backend `SessionMaker` trait stored widget session state as `base64(serialize(...))` and consumed it with `unserialize()` without an `allowed_classes` restriction. Any code path that could write to a `widget.*` session key with attacker-controlled bytes could trigger PHP object injection the next time the widget read its session state, allowing instantiation of arbitrary classes and reachable PHP gadget chains.\n\n**This issue only affects installations running with `cms.safe_mode` enabled.** Safe Mode is a niche opt-in feature, primarily used for demo installations and multi-tenant or shared-editor scenarios where untrusted users are deliberately granted access to the CMS markup editor. In standard production deployments Safe Mode is off, backend access is restricted to trusted administrators, and a markup editor can already execute arbitrary PHP directly. The session-write path that reaches this sink is gated by the Safe Mode sandbox, so installations without Safe Mode enabled are not exposed.\n\n**Scope of impact is narrow even with Safe Mode enabled.** The standard backend code paths that populate widget session state (search terms, sort options, selected IDs, filter values) wrap the input inside a known array shape before serializing, so user-supplied values never reach `unserialize()` as a controllable serialized payload. Exploitation requires the Safe Mode session-write path together with a suitable PHP gadget chain reachable from the installed dependency set. The hardening below removes the underlying object-injection sink so the class of issue is closed off regardless.\n\n### Impact\n- Arbitrary PHP code execution as the web server user, via a gadget chain deserialized from a widget session key, triggered the next time the affected widget is rendered\n- Requires `cms.safe_mode` to be enabled, and a backend user with CMS markup editing access who is not intended to be trusted as a full administrator\n- A suitable PHP gadget chain must be reachable from the installed dependency set\n- Not exploitable when Safe Mode is disabled\n\n### Patches\nThe vulnerability has been patched in v3.7.17 and v4.2.21. Two changes were applied:\n\n- `Backend\\Traits\\SessionMaker` now stores widget session state as plain JSON instead of `base64(serialize(...))`, eliminating the object-injection sink entirely for new writes. Reads transparently fall back to the legacy format for one upgrade cycle so existing sessions retain their saved widget state.\n- The legacy `unserialize()` fallback path now sets `allowed_classes =\u003e false`, so even values written before the upgrade cannot instantiate objects.\n\n### Workarounds\nIf upgrading immediately is not possible, restrict CMS markup editing access to fully trusted administrators only, the standard October CMS recommendation for any deployment.\n\n### References\n- Reported by EndlssNightmare","aliases":["CVE-2026-49400"],"modified":"2026-09-14T18:15:05.119996963Z","published":"2026-09-14T17:08:06Z","database_specific":{"cwe_ids":["CWE-502"],"severity":"LOW","github_reviewed":true,"github_reviewed_at":"2026-09-14T17:08:06Z","nvd_published_at":null},"references":[{"type":"WEB","url":"https://github.com/octobercms/october/security/advisories/GHSA-2ff2-mx52-q8wp"},{"type":"PACKAGE","url":"https://github.com/octobercms/october"}],"affected":[{"package":{"name":"october/system","ecosystem":"Packagist","purl":"pkg:composer/october/system"},"ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"3.7.17"}]}],"versions":["v1.0.319","v1.0.320","v1.0.321","v1.0.322","v1.0.323","v1.0.324","v1.0.325","v1.0.326","v1.0.327","v1.0.328","v1.0.329","v1.0.330","v1.0.331","v1.0.332","v1.0.333","v1.0.334","v1.0.335","v1.0.336","v1.0.337","v1.0.338","v1.0.339","v1.0.340","v1.0.341","v1.0.342","v1.0.343","v1.0.344","v1.0.345","v1.0.346","v1.0.347","v1.0.348","v1.0.349","v1.0.350","v1.0.351","v1.0.352","v1.0.353","v1.0.354","v1.0.355","v1.0.356","v1.0.357","v1.0.358","v1.0.359","v1.0.360","v1.0.361","v1.0.362","v1.0.363","v1.0.364","v1.0.365","v1.0.366","v1.0.367","v1.0.368","v1.0.369","v1.0.370","v1.0.371","v1.0.372","v1.0.373","v1.0.374","v1.0.375","v1.0.376","v1.0.377","v1.0.378","v1.0.379","v1.0.380","v1.0.381","v1.0.382","v1.0.383","v1.0.384","v1.0.385","v1.0.386","v1.0.387","v1.0.388","v1.0.389","v1.0.390","v1.0.391","v1.0.392","v1.0.393","v1.0.394","v1.0.395","v1.0.396","v1.0.397","v1.0.398","v1.0.399","v1.0.400","v1.0.401","v1.0.402","v1.0.403","v1.0.404","v1.0.405","v1.0.406","v1.0.407","v1.0.408","v1.0.409","v1.0.410","v1.0.411","v1.0.412","v1.0.413","v1.0.414","v1.0.415","v1.0.416","v1.0.417","v1.0.418","v1.0.419","v1.0.420","v1.0.421","v1.0.422","v1.0.423","v1.0.424","v1.0.425","v1.0.426","v1.0.427","v1.0.428","v1.0.429","v1.0.430","v1.0.431","v1.0.432","v1.0.433","v1.0.434","v1.0.435","v1.0.436","v1.0.437","v1.0.438","v1.0.439","v1.0.440","v1.0.441","v1.0.442","v1.0.443","v1.0.444","v1.0.445","v1.0.446","v1.0.447","v1.0.448","v1.0.449","v1.0.450","v1.0.451","v1.0.452","v1.0.453","v1.0.454","v1.0.455","v1.0.456","v1.0.457","v1.0.458","v1.0.459","v1.0.460","v1.0.461","v1.0.462","v1.0.463","v1.0.464","v1.0.465","v1.0.466","v1.0.467","v1.0.468","v1.0.469","v1.0.470","v1.0.471","v1.0.472","v1.0.473","v1.0.474","v1.0.475","v1.0.476","v1.1.0","v1.1.1","v1.1.10","v1.1.11","v1.1.12","v1.1.2","v1.1.3","v1.1.4","v1.1.5","v1.1.6","v1.1.9"],"database_specific":{"source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/09/GHSA-2ff2-mx52-q8wp/GHSA-2ff2-mx52-q8wp.json"}},{"package":{"name":"october/system","ecosystem":"Packagist","purl":"pkg:composer/october/system"},"ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"4.0.0"},{"fixed":"4.2.23"}]}],"database_specific":{"source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/09/GHSA-2ff2-mx52-q8wp/GHSA-2ff2-mx52-q8wp.json"}}],"schema_version":"1.9.0","severity":[{"type":"CVSS_V3","score":"CVSS:3.1/AV:N/AC:H/PR:H/UI:N/S:U/C:L/I:L/A:N"}]}