Se você ainda trata XSS como bug de lab, está analisando superfície errada.
O ataque não sumiu. Só ficou mais dependente de contexto de execução, fluxo de estado e erro de integração entre front e back.
Reflected
Reflected XSS é input que entra na requisição e volta na resposta sem encoding no contexto correto.
app.get('/busca', (req, res) => {
const q = req.query.q;
res.send(`<h1>Resultado: ${q}</h1>`);
});
Se q carregar payload com handler ou quebra de contexto, o navegador interpreta como HTML ativo e executa no origin da aplicação. Isso vira vetor pra roubo de sessão, ação autenticada e abuso de trust no cliente.
Stored
Stored XSS é pior porque persiste. O payload fica gravado e dispara toda vez que outro usuário renderiza aquela view.
await db.insert({ comment: req.body.comment });
res.send(`<p>${row.comment}</p>`);
Aqui o problema técnico é claro: dado não confiável sai de armazenamento e entra em sink HTML sem escaping contextual. Escala com audiência, então impacto não cresce linearmente com uma requisição, cresce com cada renderização futura.
DOM
DOM XSS nasce no cliente quando dado controlável cai em sink perigoso de DOM API.
<div id="out"></div>
<script>
const input = location.hash.slice(1);
document.getElementById('out').innerHTML = input;
</script>
O back pode estar 100% sanitizado e mesmo assim você ter execução no browser, porque a falha está no runtime do front. Se a vítima já está autenticada, o payload herda sessão e consegue disparar ações com credenciais válidas.
”Mas framework moderno já escapa tudo”
Escapa no fluxo padrão.
Mas, na prática, basta um dangerouslySetInnerHTML, um componente legado ou uma interpolação fora do template padrão pra quebrar a garantia. Segurança de framework não sobrevive à exceção manual mal feita.
”Mas CSP resolve tudo”
Resolve quando é estrita e consistente no produto inteiro.
Na vida real eu ainda vejo unsafe-inline, nonce faltando em rota específica e política diferente entre páginas antigas e novas. Aí CSP vira documento de intenção, não barreira confiável de exploração.
O problema real
XSS não é bug de tag. É bug de contexto e de fronteira de confiança.
Se você modela source, transformação e sink, encontra cadeia explorável de verdade. Se fica só em payload pronto, perde o bug que realmente vira incidente.
Defesa séria continua sem glamour: encoding por contexto, validação de fluxo, sanitização só quando inevitável e CSP sem exceção preguiçosa. É isso que separa frontend moderno de frontend explorável.