1001Ferramentas
🐌 Segurança

Analisador de Risco ReDoS em Regex

Analisa uma expressão regular e aponta trechos com risco de ReDoS, como quantificadores aninhados e alternâncias ambíguas, sem executá-la.

Cole o corpo puro ou a forma literal /^(a+)+$/gi — as flags são separadas sozinhas.

A análise é estática: sua expressão é compilada só para checar a sintaxe e depois lida caractere a caractere. Ela nunca é executada contra entrada gerada, e nada do que você digita sai do navegador.

Por que o retrocesso explode

JavaScript, Java, Python e PCRE usam motor com retrocesso: quando um caminho falha, ele volta e tenta a próxima divisão do mesmo texto. Em ^(a+)+$ contra trinta letras a seguidas de um ponto de exclamação, o motor precisa testar todas as formas de cortar essas letras em grupos antes de dizer não, e a conta dobra a cada letra a mais.

A checagem aqui é heurística e lê a forma da expressão, não o comportamento dela: relatório limpo não é prova de que a expressão é segura, e um achado não é prova de que dá para explorar no seu contexto. Ancorar, limitar a repetição com {0,50} e recusar entrada grande demais antes do match são as correções que sobrevivem a uma reescrita.

Onde uma regex trava com entrada curta

ReDoS é o travamento que aparece quando uma expressão regular precisa testar um número absurdo de caminhos para concluir que o texto não casa. A análise aqui é estática: a expressão é compilada só para checar a sintaxe e depois lida caractere a caractere, marcando os trechos suspeitos por posição. Nada é executado contra entrada gerada, então a aba não corre risco de congelar durante a checagem.

O caso clássico é ^(a+)+$. Contra trinta letras a seguidas de um ponto de exclamação, o motor tem que testar todas as formas de repartir essas trinta letras entre as duas repetições antes de responder que não casa, e cada letra a mais dobra a conta. Alternâncias como (a|ab)* caem no mesmo buraco, porque os dois ramos começam pelo mesmo caractere e o motor não sabe qual deles usar em cada posição.

O ponto que costuma escapar é que ancorar com ^ e $ ajuda, mas não cura: a âncora corta as tentativas em posições iniciais diferentes e não muda nada dentro do grupo aninhado. As correções que sobrevivem a uma revisão são limitar a repetição com {1,50}, deixar os ramos da alternância mutuamente exclusivos, recusar entrada acima de um tamanho antes de aplicar a regex e rodar validação pesada com timeout.

Perguntas frequentes

A ferramenta executa a minha expressão?
Só o construtor new RegExp roda, e apenas para saber se a sintaxe é válida e se as flags existem. Compilar não faz o motor procurar nada em texto nenhum. A string de ataque sugerida sai como código para você colar em um benchmark com timeout, em um processo que dê para matar, e não deve ser colada de volta no campo desta página.
Nenhum achado quer dizer que a regex é segura?
Não. A checagem lê a forma da expressão e reconhece os padrões conhecidos de retrocesso, então construções incomuns, backreferences e combinações entre grupos distantes podem passar sem alarme. Trate um relatório limpo como ausência de sinal, não como aprovação, e mantenha o limite de tamanho da entrada mesmo nas expressões que parecem tranquilas.
Dá para corrigir sem reescrever a expressão?
Em geral dá. Cortar a entrada em um tamanho máximo antes do match já derruba o custo, porque o estouro depende do comprimento do texto. Motores sem retrocesso, como RE2 e o pacote node-re2, resolvem de vez ao preço de perder lookarounds e backreferences. Em Java, dá para rodar o match em uma thread com prazo; em Node, em um worker que você encerra.

Ferramentas Relacionadas