XSS baseado em DOM
A falha está só no JavaScript do cliente: ele lê uma fonte que você controla e a joga num sink perigoso.
Nos casos anteriores, o servidor devolvia a entrada na página. No XSS baseado em DOM o servidor nem participa: a página carrega normal, e o próprio JavaScript do cliente pega um valor que você controla e o coloca num lugar que vira código.
O valor de entrada é a fonte (source). Fontes comuns: location.hash (o que vem depois do # no endereço), location.search, document.referrer, uma mensagem recebida. O lugar perigoso onde ele é usado é o sink. Sinks comuns: element.innerHTML, document.write, eval, setTimeout com string.
Um detalhe que muda tudo: o que vem depois do # (o fragmento) não é enviado ao servidor. Então um filtro no servidor, ou um firewall de aplicação, nunca vê esse valor. A falha nasce e morre no navegador.
Para achar um XSS de DOM você segue o dado: encontre a fonte no código do cliente e veja se ele chega a um sink sem ser tratado no caminho. A defesa é não jogar dado de fonte em sink de HTML: use textContent em vez de innerHTML, ou trate o valor.