- Respostas de spam preenchem cada caractere com caracteres invisíveis de largura zero. Na tela o texto parece normal; como string, fica irreconhecível.
- Nenhuma palavra-chave ou regex consegue corresponder, porque a frase que você procura não está mais contígua.
- A correção tem duas partes: remover os caracteres invisíveis antes de comparar e, à parte, marcar publicações que são sobretudo preenchimento invisível.
- O X Spam Blocker faz as duas coisas, e a segunda regra continua valendo quando o spam reescreve o script.
Este vale entender mesmo que você nunca instale nada, porque explica uma frustração de quase todo mundo que já tentou filtrar spam no X: uma resposta que é inconfundivelmente spam, que visivelmente contém a frase exata da sua lista de filtros, e que o seu filtro não pega. A publicação não está mentindo para você. O seu filtro está olhando uma string diferente da que você consegue ver.
O sintoma
Digamos que você tenha looks better than me na lista de palavras-chave, e chegue uma resposta que se lê, claramente, nobody looks better than me. O filtro não dispara. Você confere erro de digitação. Confere se a varredura está ligada. Copia o texto da publicação e cola na lista de filtros, e isso também não funciona — na verdade, agora nada corresponde.
Nesse ponto a explicação é quase sempre preenchimento. O texto visível e o texto por baixo não são a mesma coisa, e quando você copiou a publicação copiou o preenchimento junto.
Como o truque funciona
O Unicode tem uma série de caracteres deliberadamente invisíveis. Eles existem para fazer trabalhos que não são serem vistos: juntar dois emoji num só, dizer a uma escrita como letras vizinhas devem se conectar, marcar uma mudança de direção do texto. Renderizam como nada, não ocupam largura e sobrevivem a copiar e colar.
Então um spammer insere um entre cada caractere da mensagem. Uma frase de oito caracteres vira uma string de vinte e cinco, dos quais dezessete são invisíveis. Para quem lê, são oito caracteres. Para um filtro, é uma sequência em que duas letras da sua palavra-chave nunca ficam lado a lado.
| Visível | Caracteres reais | |
|---|---|---|
| O que quem lê vê | 8 | — |
| O que o filtro lê | 8 | 25, 17 deles invisíveis |
| Contém a sua palavra-chave? | Sim | Não |
Não custa nada ao spammer — é um localizar e substituir no script que publica as respostas — e derrota todo filtro ingênuo de uma vez.
Os caracteres envolvidos
Em amostras tiradas de spam de resposta ao vivo, o preenchimento é quase sempre um destes três, revezados para não parecer mecânico:
| Ponto de código | Nome | Trabalho legítimo |
|---|---|---|
| U+200C | Zero-width non-joiner | Impede letras de se juntarem em persa, árabe e devanágari |
| U+200D | Zero-width joiner | Junta emoji num só glifo, por exemplo uma família ou uma profissão |
| U+2060 | Word joiner | Impede uma quebra de linha sem acrescentar um espaço |
Há outros da mesma família — a marca de ordem de bytes U+FEFF, as marcas de direção U+200E e U+200F, o hífen suave U+00AD, o separador de vogal mongol U+180E, os overrides bidirecionais na faixa U+202A–U+202E. Um filtro caprichoso tem de dar conta de todos, porque aquele que ele deixar passar é o que será usado em seguida.
Veja com os próprios olhos em vinte segundos
Você não precisa de ferramenta nenhuma para isso. Abra uma resposta de spam, selecione o texto, copie e cole num lugar que informe o comprimento — um console do navegador é o mais fácil:
const s = `paste the copied reply here`
console.log(s.length)
console.log((s.match(/[--]/g) || []).length)Uma frase normal devolve um segundo número igual a zero. Spam preenchido devolve algo perto do primeiro número. Num fio amostrado, quatro respostas de onze carregavam de 52 a 67 caracteres invisíveis cada — cerca de 80% da string bruta — enquanto as outras sete mediam exatamente zero. Não há zona cinza no meio; é isso que torna detectável.
Por que todo filtro de texto falha nisso
Vale ser preciso aqui, porque a falha não é um bug de nenhum filtro em particular. Três defesas quebram ao mesmo tempo:
- Palavras-chave exatas. Morrem na hora. A substring não existe.
- Regex "frouxos" que permitem um vão entre caracteres — algo como
b.{0,3}e.{0,3}t— sobrevivem a um caractere de enchimento por vão e morrem em seis. - Palavras-chave copiadas e coladas. Copiar a frase do spam traz o preenchimento junto, então a palavra-chave nova só corresponde àquela publicação, com aquele arranjo exato de enchimentos.
Há uma quarta falha fácil de perder. Em JavaScript, um quantificador como .{0,3} conta unidades de código UTF-16, não caracteres — e um emoji são duas unidades de código. Então um regex frouxo escrito para tolerar três caracteres de vão na verdade tolera um emoji, e é por isso que espaçar uma palavra com emoji também derrota um padrão frouxo.
Correção um: remover os caracteres antes de comparar
O lugar certo de resolver isso é antes de qualquer regra rodar. O X Spam Blocker monta uma cópia limpa do texto que está prestes a comparar: caracteres invisíveis removidos e depois normalização Unicode NFKC, para que letras de largura total, circuladas e subscritas ou sobrescritas voltem às simples. Em seguida monta uma terceira cópia, mais apertada, com todos os espaços, a pontuação e os emoji removidos, deixando só letras e dígitos.
As regras são tentadas contra as três, e suas palavras-chave são normalizadas do mesmo jeito. Isso tem três consequências úteis:
- Sua lista atual de palavras-chave passa a funcionar em spam preenchido sem você mudar nada.
- Uma palavra-chave que você copiou de uma resposta de spam, preenchimento incluso, ainda funciona como filtro.
- Espaçar uma palavra com emoji — a variante que derrota regex frouxos — é tratado pela cópia apertada, que descarta emoji por completo.
Nada na página é modificado. A limpeza vale só para a cópia usada na comparação.
Correção dois: detectar a forma, não as palavras
Remover resolve o spam de hoje. Não resolve o do mês que vem, porque o texto vai mudar e a sua lista de palavras-chave não terá acompanhado. Então há uma segunda regra, independente, que ignora o texto por completo:
Se pelo menos 30% dos caracteres de uma publicação forem invisíveis suspeitos, e houver pelo menos 6 deles, e a publicação tiver pelo menos 8 caracteres — marque. Nenhuma palavra-chave é necessária.
Essa é a regra inteira, e o valor dela é que preenchimento invisível pesado é em si o sinal de spam. Ninguém escreve uma publicação normal que seja um terço de caracteres invisíveis. A distância medida é enorme: as respostas de spam amostradas marcaram 53% a 60% no conjunto estreito de caracteres, e publicações comuns marcaram zero. Um limiar de 30% fica no meio de uma faixa vazia bem larga.
No painel é o interruptor Detectar também publicações preenchidas com caracteres invisíveis, ligado por padrão. Quando dispara, o candidato e o item do registro dizem "Ofuscação com caracteres invisíveis" com a porcentagem medida, para você distinguir de uma palavra-chave sua. Correspondências de palavra-chave têm prioridade, então quando as duas disparariam você recebe a palavra específica — o que é mais útil na hora de depurar uma regra.
O problema do emoji, e por que a regra é mais estreita do que parece
Aqui está a parte que faz ou desfaz uma regra assim. O juntador de largura zero U+200D não é só uma ferramenta de spam — é a cola dos emoji compostos. Um emoji de família são três pessoas visíveis unidas por dois caracteres U+200D. Meça de forma ingênua e você obtém 40% de caracteres invisíveis: um falso positivo na publicação mais inocente que se pode imaginar.
Por isso a regra de detecção usa um conjunto de caracteres deliberadamente mais estreito do que a remoção. Três categorias inteiras ficam de fora da contagem como evidência:
- U+200D, o juntador de largura zero — porque emoji compostos estão cheios dele.
- U+FE00–U+FE0F, os seletores de variação — o caractere invisível que faz ❤️ renderizar em cor.
- U+E0020–U+E007F, os caracteres de tag — usados por bandeiras de subdivisão como 🏴.
Tirar esses três deixa o spam de preenchimento ainda na casa dos cinquenta e tantos por cento, porque U+200C e U+2060 sozinhos bastam para condenar. Verificado contra sequências de emoji de família, corações coloridos, a bandeira do arco-íris, emoji de profissão, bandeiras de subdivisão, texto persa usando U+200C como ortografia real e publicações muito curtas preenchidas de propósito, todas medem 0,0%.
Essa é a troca que vale copiar se você construir algo parecido: uma regra de remoção pode ser gulosa, porque uma remoção errada não custa nada. Uma regra de detecção tem de ser mesquinha, porque uma marcação errada te custa uma conta de verdade.
Os truques aparentados, já que você está aqui
Preenchimento invisível é a evasão mais comum, mas não a única, e a mesma normalização dá conta da maior parte da família:
- Letras de largura total e decoradas. Texto Fullwidth, letras circuladas, negrito matemático — tudo volta a letras simples sob NFKC.
- Emoji como separadores. Uma palavra partida com emoji entre os caracteres, o que a cópia apertada resolve apagando-os.
- Homóglifos. Um а cirílico no lugar do a latino, um ο grego no lugar do o. O NFKC não dobra estes — são letras genuinamente diferentes — então continuam uma lacuna real. Uma substituição por homóglifo também é, de forma útil, algo para o qual a regra de forma pode ser apontada no futuro.
Para os filtros que ficam em cima de tudo isso, veja bloquear contas do Twitter por palavra-chave ou regex, ou as listas prontas em bloquear golpes de cripto e bots de spam no X.
Perguntas frequentes
O que são caracteres de largura zero?
Caracteres Unicode de verdade que não ocupam espaço quando renderizados. Existem por motivos legítimos — juntar emoji, controlar como letras persas e devanágari se conectam, marcar a direção do texto — mas, por serem invisíveis e sobreviverem a copiar e colar, também são um jeito conveniente de quebrar um filtro de texto.
O X consegue detectar isso sozinho?
O X claramente filtra parte, já que o mesmo spam muitas vezes acaba removido. Mas caracteres invisíveis são legítimos em contextos suficientes para uma plataforma não poder simplesmente baní-los, e o spam de resposta que sobrevive tempo bastante para ser visto já fez o trabalho. Um filtro do seu lado não precisa esperar por ninguém.
Remover caracteres invisíveis estraga publicações normais?
Não de um jeito que você notaria, porque a remoção só acontece na cópia usada para comparar — nada na página é alterado. A detecção é mais estrita: o conjunto de caracteres usado na regra de preenchimento oculto deixa de fora de propósito os juntadores de emoji e os seletores de variação, então uma publicação cheia de emoji nunca é marcada por ela.
Qual proporção conta como ofuscada?
30% ou mais da string sendo caracteres invisíveis suspeitos, com pelo menos seis deles, e o texto com pelo menos oito caracteres. Respostas de spam medidas ficam em 53–60%. Publicações comuns, inclusive as cheias de emoji e bandeiras, medem zero.
Por que o registro mostra uma porcentagem em vez de uma palavra-chave?
Porque nenhuma palavra-chave correspondeu — a publicação foi marcada pela forma. O registro mostra "Ofuscação com caracteres invisíveis" com a proporção medida, o que diz que a regra que disparou foi a regra de forma, não uma das suas.
Bloqueie contas de spam no X em massa, depois de confirmar
Extensão gratuita do Chrome. Sem conta, sem servidor, sem rastreamento.


