Esta é uma análise de regressão entre o Paytium 5.0.3 e o Paytium 5.0.5. O objetivo foi verificar se um valor controlável relacionado a descontos alcançava um sink HTML inseguro e se a versão posterior neutralizava o mesmo caminho.
esc_html(). Portanto, este caso é documentado como
corrigido em 5.0.5, sem alegar uma nova CVE.
O fluxo vulnerável em 5.0.3
No processamento do pagamento, o Paytium monta os dados do desconto a partir do
formulário. Entre esses dados está o código do desconto, associado ao campo
discount_code.
$discount_data = array(
'discount_code' => $_POST['pt-discount']['code'],
// ...
);
O valor é persistido junto aos dados do pagamento. Mais tarde, a tela de detalhes
da assinatura recupera esse valor por meio de
$payment->get_discount_code() e o concatena diretamente no HTML.
echo $payment->get_discount_value()
. ' (code: ' . $payment->get_discount_code() . ')';
Esse echo é o sink final: o conteúdo controlado termina em um contexto
de texto HTML sem escape de saída. Quando um administrador abre o detalhe da
assinatura que contém o valor armazenado, o navegador interpreta a marcação como
parte da página.
Correção confirmada em 5.0.5
Na versão 5.0.5 comparada no laboratório, o mesmo ponto foi alterado para escapar o valor antes da saída:
echo esc_html(
$payment->get_discount_value()
. ' (code: ' . $payment->get_discount_code() . ')'
);
A correção é relevante porque ocorre no sink e no contexto correto. Mesmo que um valor antigo permaneça no banco de dados, ele deixa de ser interpretado como HTML nessa tela. O resultado esperado é a exibição literal dos caracteres especiais, em vez da execução de JavaScript.
PoC segura para laboratório
A validação foi feita apenas em uma instalação própria. O marcador utilizado para confirmar a hipótese foi um valor inofensivo com caracteres HTML:
<img src=x onerror=alert(document.domain)>
Em 5.0.3, o valor armazenado alcançava o detalhe da assinatura como marcação.
Em 5.0.5, a mesma sequência deve aparecer como texto escapado, por exemplo
<img ...>, sem execução. A PoC não deve ser usada contra
sites de terceiros e não inclui cookies, tokens ou credenciais.
Boas práticas de correção
A correção mínima é aplicar escape contextual no ponto de saída: esc_html()
para texto, esc_attr() para atributos e esc_url() para URLs.
Também é recomendável validar a estrutura dos dados na entrada, restringir chaves
de metadados a uma allowlist e testar cada caminho de persistência até seu sink final.