Potential RCE with a compromised security key in craft/cms
Priorize a correção. Ela está sob exploração confirmada pelo CISA.
Apply mitigations per vendor instructions or discontinue use of the product if mitigations are unavailable.
Resumo
Falha de code injection (CWE-94) no fluxo de restauração de backup de banco de dados do Craft CMS, que permite RCE completo no servidor — mas apenas se a security key da aplicação já estiver comprometida. O CVSS de 8.1 é alto, porém o pré-requisito (posse da security key) restringe bastante quem está realmente exposto: não é uma falha explorável remotamente por um atacante anônimo sem esse segredo.
Detalhamento técnico
O problema está em UpdaterController::actionRestoreDb(). O método chamava Craft::$app->getDb()->restore($this->data['dbBackupPath']) passando diretamente um caminho de arquivo vindo de dados controlados pelo cliente, sem validar se esse caminho existia ou se estava contido dentro do diretório oficial de backups (storage/backups). O comando de restore do Yii2/Craft monta e executa uma chamada de shell (mysql/pg_restore, dependendo do driver de banco) usando esse caminho como argumento — se o valor puder ser manipulado, o atacante injeta comando arbitrário ou faz o processo tratar um arquivo arbitrário do disco como se fosse um dump de banco, alcançando execução de código no servidor. É classificado pela CISA como CWE-94, code injection causado por validação inadequada do caminho de backup do banco.
O campo $this->data que alimenta o dbBackupPath não é um parâmetro de request comum e aberto: no fluxo do Updater, esses dados normalmente são protegidos/assinados usando a security key da aplicação (o segredo criptográfico configurado em config/general.php ou via variável de ambiente, usado por Craft::$app->getSecurity() para validar/decriptar payloads). Isso explica por que a falha só é explorável quando a security key já foi comprometida: sem ela, o atacante não consegue forjar um payload de dados válido que o controlador aceite processar com um dbBackupPath arbitrário.
A correção (commit e59e22b) adiciona duas verificações antes de chamar restore(): file_exists($backupPath) e FileHelper::isWithin($backupPath, Craft::$app->getPath()->getDbBackupPath()), lançando BadRequestHttpException se o caminho não existir ou estiver fora do diretório de backups esperado. Ou seja, o patch não elimina a necessidade de proteger a security key — ele fecha a porta de escape de diretório/injeção que a posse da key abria.
Como é explorada
Pré-requisito indispensável e raramente destacado no título da CVE: o atacante precisa já possuir a security key da instalação Craft. Isso normalmente vem de exposição de .env, config/general.php, repositórios de código vazados, backups de arquivos acessíveis publicamente, ou outra falha anterior que leia arquivos de configuração. Sem a key, o endpoint do Updater não aceita um payload de dados forjado e a cadeia de exploração não se completa — por isso AV:N mas AC:H no vetor CVSS.
Com a key em mãos, o atacante forja o payload de dados que o UpdaterController espera (o campo que carrega dbBackupPath), definindo esse caminho para um arquivo sob seu controle ou para explorar a ausência de contenção de diretório, disparando a rotina de restauração de banco. Como o valor do caminho chega sem sanitização até o comando de restore executado via shell, isso resulta em execução de código arbitrário no servidor, com o mesmo nível de privilégio do processo PHP/Craft (potencialmente todo o container ou VM da aplicação).
A CVE está no catálogo KEV da CISA (adicionada em 2025-02-20, prazo de correção 2025-03-13), confirmando exploração ativa observada, embora a CISA não indique se há uso em campanhas de ransomware. A necessidade de posse prévia da security key sugere que a exploração em massa provavelmente ocorreu em conjunto com outras falhas ou exposições que vazaram esse segredo — não é um ataque de um único passo contra qualquer instalação Craft na internet.
Versões
Como se proteger
Atualizar para Craft 5.5.8 (ramo 5) ou 4.13.8 (ramo 4), que adicionam validação de existência e contenção do caminho de backup dentro do diretório oficial antes de executar o restore. Essa é a correção real da causa raiz (a falta de validação do path) e deve ser aplicada independentemente de você acreditar que sua security key está segura.
Se a atualização não for possível agora, o fornecedor recomenda rotacionar a security key imediatamente e garantir que ela não fique exposta (fora de repositórios versionados, fora do webroot, lida por variável de ambiente). Isso remove o pré-requisito de exploração — mas é mitigação parcial: se a causa que expôs a key originalmente persistir (por exemplo, .env acessível via HTTP, painel de configuração exposto, backup de código-fonte público), uma nova key pode ser comprometida da mesma forma e o problema reaparece.
Não funciona como mitigação apenas restringir acesso ao painel administrativo do Craft sem tratar a exposição da security key nem aplicar o patch — a falha de validação do caminho de backup continua presente até a atualização, e a chave, uma vez vazada, compromete toda a proteção que dados assinados oferecem no restante da aplicação, não só neste endpoint.
Como detectar
Nos logs de erro do Craft/PHP, procure por exceções BadRequestHttpException com mensagem 'Invalid backup path' — isso indica que o patch está ativo e bloqueou uma tentativa de path fora do diretório de backups ou inexistente; sua ausência em versão não corrigida não significa ausência de tentativa, apenas que o comando de restore não logava esse tipo de rejeição antes do patch. Verifique também requisições HTTP dirigidas às rotas de ações do controller de Updater (fluxo de atualização/restore do Craft) fora do horário normal de manutenção/deploy.
Não há assinatura de payload pública conhecida, já que a exploração depende de um segredo específico da instalação (a security key) — não existe um indicador de comprometimento genérico aplicável entre diferentes instalações Craft. O sinal mais confiável de risco não é tráfego, e sim auditoria: verificar se a security key da instalação já foi exposta em algum momento (histórico de repositório, backups públicos, logs de erro com stack trace, arquivos .env acessíveis).