Por que slugs de WordPress com hifens disparam o OWASP CRS no WAF (e como excluir o parâmetro)
Publicado em 27 de julho de 2026

O sintoma: bloqueios legítimos no WAF
Auditando 24h de logs do WAF, 13 requisições foram bloqueadas. Duas eram ataque real (um scanner procurando .env). As outras 11 eram tráfego legítimo do próprio site: chamadas de ISR/revalidação do Next.js para a API do WordPress com query string ?slug=algum-titulo-longo-com-varios-hifens.
# distribuição dos bloqueios por regra (24h)
ruleId 942432 → 7 (SQLi - special chars)
ruleId 942431 → 2 (SQLi - char anomaly)
ruleId 930130 → 2 (LFI)
.env scanner → 2 (ataque real — manter bloqueado)A causa: hifens pontuam como anomalia de SQLi
As regras de SQL injection do OWASP CRS pontuam caracteres especiais e a 'anomalia' de uma string. Um slug de WordPress longo — vários hifens, números, palavras concatenadas — acumula pontos suficientes para cruzar o threshold das regras 942431/942432, mesmo sem nada de malicioso. O parâmetro slug simplesmente não estava na lista de exclusões do CRS.
OWASP CRS é pontuação, não certeza. Um valor benigno mas 'estranho' (slug com hifens, base64, JWT) acumula score e vira falso positivo. A correção é excluir o parâmetro específico, não baixar a sensibilidade global.
O fix: excluir o slug em TODAS as 141 capabilities
Na OCI, a exclusão precisa ser aplicada em cada uma das 141 capabilities do CRS — não há um único toggle. Isso se faz via API/CLI, lendo a policy, adicionando o argumentName na exclusão de cada capability, e reescrevendo com o etag. Como o WAF é grande, um patch inline em Python é mais robusto que editar à mão:
import json, subprocess
pid = "ocid1.waaspolicy.oc1..aaaaEXAMPLE"
pol = json.loads(subprocess.check_output(
["oci","waf","web-app-firewall-policy","get","--waf-policy-id",pid]))
data, etag = pol["data"], pol["etag"]
# adiciona 'slug' às argument-name exclusions de cada protection capability
for cap in data["request-protection"]["rules"][0]["protection-capabilities"]:
ex = cap.setdefault("exclusions", {}).setdefault("args", [])
if "slug" not in ex:
ex.append("slug")
subprocess.run(["oci","waf","web-app-firewall-policy","update","--waf-policy-id",pid,
"--request-protection", json.dumps(data["request-protection"]),
"--if-match", etag])Armadilha: se a policy estiver sendo modificada, a update retorna 409 ("being modified") — é preciso aguardar e reenviar com o etag atualizado. Validamos com um loop de 5 slugs reais longos: todos retornaram 200, e o scanner de .env continuou bloqueado.
Lições
1. Slugs longos com hifens viram falso positivo de SQLi. O CRS pontua caracteres especiais; permalinks do WordPress acumulam score sem serem maliciosos.
2. Exclua o parâmetro, não baixe a sensibilidade. Adicionar 'slug' às exclusions preserva a proteção para o resto da requisição.
3. Na OCI, a exclusão é por capability (141). Não há toggle único; um patch via API com etag (e retry no 409) aplica em todas.
Conclusão
WAF que bloqueia o próprio site é tão problema quanto WAF que deixa o ataque passar. O OWASP CRS estava certo em desconfiar de strings estranhas — só não sabia que aquele ?slug= era um título de post, não um payload. Excluir o parâmetro nas 141 capabilities devolveu o ISR sem abrir mão de barrar o scanner de .env que aparecia no mesmo log.