A sigla XSS vem do inglês cross-site scripting; usa-se X em vez de C para não confundir com as folhas de estilo CSS. É uma falha de injeção: o site insere na página um dado vindo de fora sem neutralizá-lo, e o navegador o interpreta como código. O MITRE a cataloga com o identificador CWE-79. Como o script parece vir do próprio site, o navegador lhe dá a mesma confiança que ao resto da página.
Como funciona um ataque XSS
Tudo começa com um valor que o atacante controla: um parâmetro de URL, um campo de formulário, um comentário, um cabeçalho HTTP gravado em estatísticas. Se o código exibe esse valor bruto, uma string como <script>…</script> ou um atributo onerror="…" se torna executável. O script pode então ler o conteúdo da página, enviar requisições em nome da pessoa logada, alterar o que ela vê ou redirecioná-la para outro site.

Em um site WordPress, o alvo preferido é o administrador. Um script executado na sessão dele pode criar uma conta, instalar um plugin ou mudar uma configuração, sem nunca conhecer a senha: o próprio navegador envia os cookies de login com cada requisição.
Os tipos de XSS
- XSS armazenado (persistente): o script é gravado no servidor, no banco de dados por exemplo, e devolvido a cada exibição. Não se exige nenhuma ação especial da vítima, basta abrir a página.
- XSS refletido: o script viaja na requisição, muitas vezes um link armadilhado, e o servidor o copia imediatamente na resposta. A vítima precisa clicar.
- XSS baseado em DOM: é o JavaScript da página que insere um dado não confiável, como o fragmento de uma URL. O servidor pode não ver nada passar.
A OWASP também descreve o XSS “cego” (blind XSS): uma variante armazenada que dispara mais tarde, em uma interface que o atacante não vê. É exatamente o caso dos logs, estatísticas e formulários recebidos que se consultam no Painel. Os exemplos reais de XSS em plugins populares mostram que esse cenário não tem nada de teórico.
No WordPress: escapar no último momento
A documentação para desenvolvedores do WordPress define uma regra simples: escapar o mais tarde possível, no momento em que o dado é exibido, com a função que corresponde ao contexto.
| Contexto de exibição | Função |
|---|---|
| Texto dentro de um elemento HTML | esc_html() |
| Valor de um atributo | esc_attr() |
| URL em href ou src | esc_url() |
| JavaScript inline | esc_js() |
| Conteúdo de um textarea | esc_textarea() |
| HTML com algumas tags permitidas | wp_kses(), wp_kses_post() |
<h2><?php echo esc_html( $titulo ); ?></h2>
<a href="<?php echo esc_url( $link ); ?>" title="<?php echo esc_attr( $info ); ?>">Ver</a>
Validar e sanitizar as entradas continua sendo útil, mas não substitui esse escape na saída: um mesmo valor pode ser exibido em vários contextos.
Como se proteger sem mexer no código
- Atualizar rapidamente plugins e temas: os XSS explorados em massa costumam mirar versões já corrigidas.
- Manter poucas contas com privilégios e excluir as que não são mais usadas.
- Ficar de olho no surgimento de novos administradores, sinal frequente de um XSS explorado.
- Adicionar uma política de segurança de conteúdo, sabendo que uma versão rígida, que proíbe scripts inline, é difícil de manter com o WordPress. Nosso guia de cabeçalhos de segurança HTTP para WordPress detalha as opções.
- Um firewall de aplicação web pode barrar payloads conhecidos, sem garantia contra uma variante inédita.
O WP Masquerade Pro envia cabeçalhos de segurança, incluindo uma CSP básica opcional. Essa CSP não restringe os scripts: portanto, não bloqueia um XSS. O WP Masquerade não é um firewall de aplicação nem um corretor de código; só a atualização do componente com defeito fecha a falha.
Erros comuns
- Confundir XSS e CSRF: o segundo faz o navegador enviar uma requisição forjada, sem executar script na página. Já um XSS permite contornar as proteções anti-CSRF, pois o script lê os tokens da página.
- Achar que um dado é “interno” porque aparece no painel de administração: um cabeçalho HTTP ou uma URL visitada vêm de fora.
- Usar
esc_html()em um atributo ouesc_attr()para uma URL: cada contexto tem a sua função. - Pensar que a proteção contra injeção de SQL basta: um dado bem gravado no banco pode continuar perigoso na exibição.