Uma regex pode responder instantaneamente em exemplos comuns e travar um worker com uma string específica. Catastrophic backtracking ocorre quando o motor explora muitas formas de distribuir os mesmos caracteres entre partes ambíguas. Se todas as opções falham perto do final, o custo pode crescer de forma exponencial. Em endpoints públicos, isso se torna risco de ReDoS.

Backtracking é uma estratégia normal

Motores tradicionais tentam um caminho e voltam quando o restante do padrão falha. Esse mecanismo suporta quantificadores, alternativas, grupos e lookarounds.

O problema não é voltar uma vez. É existir um número enorme de caminhos equivalentes para a mesma entrada.

Quantificadores aninhados são suspeitos

Padrões como (a+)+ permitem dividir uma sequência de muitas formas. Quando o caractere final esperado não aparece, o motor testa combinações antes de desistir.

Nem todo aninhamento é vulnerável, mas ele merece revisão. Pergunte se as partes consomem o mesmo conjunto de caracteres.

Alternativas sobrepostas também custam

(ab|a)+ oferece caminhos parecidos. Uma falha tardia faz o motor reconsiderar divisões anteriores. Ordenar alternativas pode ajudar, mas eliminar sobreposição é melhor.

Se a regra não pode ser expressa sem muita ambiguidade, divida a validação ou use parser.

Restrinja o que cada parte consome

Para ler até uma vírgula, [^,]* é mais previsível que .*. Anchors e limites de comprimento também reduzem o espaço de busca.

Essa especificidade melhora performance e explica melhor o formato esperado.

O motor altera as garantias

Alguns motores oferecem grupos atômicos, quantificadores possessivos e timeout. Outros evitam backtracking por design, mas suportam menos recursos. A escolha do runtime importa para entradas não confiáveis.

Timeout é proteção de último nível. Ele limita dano, mas não corrige o padrão ambíguo.

Teste falhas quase válidas

O pior caso costuma ser uma entrada que combina por muito tempo e falha no último caractere. Inclua prefixos repetitivos, delimitadores ausentes e tamanhos próximos do limite. Meça tempo.

Se dobrar o tamanho multiplica o tempo de forma explosiva, o padrão precisa ser reescrito.

ReDoS é um problema de segurança

Um atacante envia strings que ocupam threads ou processos. Formulários, filtros, busca e validações de rota são superfícies comuns. Sob concorrência, poucas requests podem reduzir a capacidade do serviço.

Size limits, rate limiting, timeout, isolamento e padrões seguros se complementam.

Simplificar costuma ser a melhor correção

Valide comprimento primeiro, caracteres depois e regras de domínio por último. Essa decomposição elimina muitos padrões com quantificadores aninhados e melhora mensagens.

Para formatos estruturados, parser linear é mais previsível. Regex não precisa resolver todo problema textual.

Observe tempo de validação

Métricas e logs de timeout podem revelar regressões antes de um incidente. Entradas rejeitadas muito lentamente são um sinal importante, mesmo que o resultado funcional seja correto.

Após corrigir, mantenha a string problemática como teste. Ela transforma um incidente em proteção permanente.

Limites de entrada reduzem a superfície

Um e-mail, slug ou código não precisa ter megabytes. Rejeitar comprimentos impossíveis antes da regex reduz CPU e memória. A regra deve ser aplicada também em imports e jobs, não somente no endpoint público.

Rate limiting complementa o limite individual. Um atacante pode usar muitas entradas pequenas e caras, mesmo que nenhuma ultrapasse o tamanho máximo.

Timeout não é a correção principal

Interromper uma regex lenta protege o processo, mas deixa o padrão ambíguo e pode produzir falhas para usuários legítimos. A correção durável remove caminhos equivalentes, usa classes exclusivas ou divide a validação.

O timeout continua útil como defesa em profundidade e como sinal de observabilidade, não como justificativa para manter um padrão exponencial.

ReDoS pode existir em dependências

Validadores de terceiros, routers e bibliotecas também usam regex. Uma aplicação pode não possuir o padrão vulnerável diretamente. Atualizações de dependência e advisories de segurança precisam fazer parte da manutenção.

Testes de carga com payloads conhecidos ajudam a confirmar que a correção da biblioteca realmente protege o caminho completo.

Isolamento reduz o raio de impacto

Processar conteúdo pesado em workers separados com limites de CPU e memória evita que uma validação cara derrube todo o servidor web. Essa arquitetura não substitui o conserto do padrão, mas protege serviços críticos contra uma regressão desconhecida.

Filas e workers também precisam de rate limit e observabilidade. Mover o problema para background sem limites apenas muda onde a saturação acontece.

Revisões automatizadas podem encontrar sinais

Linters e scanners detectam alguns quantificadores aninhados e alternativas suspeitas. Eles geram falsos positivos, mas são úteis para direcionar revisão humana. O resultado deve ser analisado junto com o motor e os limites de entrada.

Registrar a justificativa quando um alerta é aceito evita que a mesma discussão se repita e deixa claro quais garantias tornam o padrão seguro naquele contexto.

Performance é parte do contrato

Uma regex de produção deve responder em tempo aceitável para entradas válidas, inválidas e maliciosas. Menos ambiguidade, limites claros e testes de falha tornam essa propriedade verificável.

Pensar como o motor é a chave: reduza caminhos possíveis antes de depender de mais hardware ou timeouts.