You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[P2·G2·U1][security] core/detector.py:1128 — regex de override de 3º compilada sem guard ReDoS (auto-DoS via plugin pattern) #829
Eixos:P2 (label) · G2 (gravity — auto-DoS do scanner, mas requer padrão de 3º malicioso/descuidado) · U2 (não-urgente — superfície de plugin executável é roadmap, ver #606) · CodeQL-class py/redos (P0 SAST).
Problema
core/detector.py:1128 compila padrão de override fornecido por 3º/plugin com re.compile(pat)cru — sem timeout, sem checagem de complexidade. O validador de plugin verifica schema (name/pattern presentes), não segurança do pattern. Um padrão como (a+)+$ em conteúdo adversário → backtracking catastrófico, trava o scanner (ReDoS / auto-DoS).
Contraste (o time JÁ sabe disso)
Os patterns embutidos (CPF/CNPJ/email/cartão) são lineares e seguros — quantificadores finitos {n}, âncoras \b, sem aninhamento ambíguo (há comentário explícito de hardening py/redos ~core/detector.py:400). O hardening não foi estendido ao caminho de override de 3º. Vetor de ReDoS = exclusivamente o pattern de parceiro.
Evidência (origin/main, verificado 2026-06-11)
core/detector.py:1128 — re.compile(pat) em pattern de override sem guard.
Validador de plugin: schema-only, sem análise de complexidade/ReDoS.
Fix
Compilar override com timeout/limite (ex.: lib regex com timeout=, ou worker com deadline), OU rejeitar patterns com aninhamento de quantificador detectável no validador, OU ambos.
Documentar no futuro PLUGIN_AUTHOR_GUIDE o contrato de pattern seguro.
Relacionado: #606 (plugin hook infra). Cross-validated read-only por Claude Code (Fable round-3 A1). Fix → Cursor.
Confirmado exato (@ main): overrides de 3º entram via _load_regex_overrides(regex_overrides_path) (core/detector.py:1123-1125), são mergeados em self.patterns e compilados crus em core/detector.py:1128 (re.compile(pat)), sem guard. O hardening ReDoS dos built-ins fica em core/detector.py:403 (re.compile(p, re.I) do chord) — não cobre o caminho de override. Achado validado.
changed the title [-][P2·G2·U2][security] core/detector.py:1128 — regex de override de 3º compilada sem guard ReDoS (auto-DoS via plugin pattern)[/-][+][P2·G2·U1][security] core/detector.py:1128 — regex de override de 3º compilada sem guard ReDoS (auto-DoS via plugin pattern)[/+]on Jun 11, 2026
Nota de design (Claude Code, ao ver o PHONE_BR falhar na guarda): o scanner star-height char-a-char é a abordagem certa (safe-regex/eslint fazem isso; regex-sobre-regex quebra em \+/\(/classes). Mas PHONE_BR é built-in curado (detector.py:403, já hardened) — rejeitá-lo é falso-positivo sobre pattern confiável = regressão.
O threat model do #829 é o override de 3º (detector.py:1128, _load_regex_overrides), não os built-ins. Recomendação:
(a) preferida: aplicar a guarda só a override/plugin patterns; built-ins isentos (curados ≠ input não-confiável). Elimina o PHONE_BR de raiz e casa com o vetor real (ReDoS = input externo).
(b) se for defense-in-depth (guarda em todos): teste de regressão obrigatório asserindo que todos os DEFAULT_PATTERNS passam — calibra a guarda pra nunca rejeitar curado.
Casa com o PLUGIN_AUTHOR_GUIDE (#611): o contrato de pattern seguro é exigência pro autor de plugin, e o auto-teste ReDoS <100ms é dele rodar — reforça aplicar a guarda na fronteira não-confiável.
Activity
FabioLeitao commentedon Jun 11, 2026
Confirmado exato (@
main): overrides de 3º entram via_load_regex_overrides(regex_overrides_path)(core/detector.py:1123-1125), são mergeados emself.patternse compilados crus emcore/detector.py:1128(re.compile(pat)), sem guard. O hardening ReDoS dos built-ins fica emcore/detector.py:403(re.compile(p, re.I)do chord) — não cobre o caminho de override. Achado validado.[-][P2·G2·U2][security] core/detector.py:1128 — regex de override de 3º compilada sem guard ReDoS (auto-DoS via plugin pattern)[/-][+][P2·G2·U1][security] core/detector.py:1128 — regex de override de 3º compilada sem guard ReDoS (auto-DoS via plugin pattern)[/+]FabioLeitao commentedon Jun 11, 2026
Nota de design (Claude Code, ao ver o PHONE_BR falhar na guarda): o scanner star-height char-a-char é a abordagem certa (safe-regex/eslint fazem isso; regex-sobre-regex quebra em
\+/\(/classes). Mas PHONE_BR é built-in curado (detector.py:403, já hardened) — rejeitá-lo é falso-positivo sobre pattern confiável = regressão.O threat model do #829 é o override de 3º (
detector.py:1128,_load_regex_overrides), não os built-ins. Recomendação:DEFAULT_PATTERNSpassam — calibra a guarda pra nunca rejeitar curado.Casa com o
PLUGIN_AUTHOR_GUIDE(#611): o contrato de pattern seguro é exigência pro autor de plugin, e o auto-teste ReDoS <100ms é dele rodar — reforça aplicar a guarda na fronteira não-confiável.Merge pull request #842 from FabioLeitao/fix/redos-guard