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.