Skip to content

fix: prevent stack exhaustion from deeply nested brace patterns - #87

Open
akahungryy wants to merge 1 commit into
micromatch:masterfrom
akahungryy:codex/fix-braces-stack-exhaustion-20261009
Open

akahungryy wants to merge 1 commit into
micromatch:masterfrom
akahungryy:codex/fix-braces-stack-exhaustion-20261009

Conversation

@akahungryy

Copy link
Copy Markdown

Deeply nested patterns within the existing length limit exhaust the stack in recursive AST processing (GHSA-vfj7-8cjw-p6xm). The failure reproduces in compile, expand and stringify with 3,000 nested braces.

This change limits brace and parenthesis nesting to 100, with a maxDepth option that can lower the limit but cannot raise the safety cap. Compile, expand and stringify also enforce the limit for caller-provided ASTs, and expansion detects cyclic parent chains. Excessive string nesting throws SyntaxError; excessive AST depth and parent cycles throw RangeError.

The intentional compatibility change is rejection of patterns nested beyond 100 levels. This bounds the recursive walkers rather than replacing them with iterative implementations. Expansion-size risks remain outside this patch.

Validation on Node 24:

  • Full upstream npm test: 908 passing, zero failures.
  • Focused parse/compile/expand/stringify tests: 48 passing.
  • Bounded children with --stack-size=512: all four public APIs reject 3,000-level inputs with the intended guard errors; AST-cycle and option-clamp checks pass.
  • Independent read-only security review found no stack-overflow bypass in the affected paths.

The existing Node 8 assertion shim is extended for doesNotThrow; Node 8 runtime compatibility has not been exercised. No version bump is included; a maintainer release is still required.

@ulises-jeremias

Copy link
Copy Markdown

Independent validation on the current head d44b9b1: npm test passes on Node 24.17.0 (908 passing). With --stack-size=512, I also exercised parse, compile, expand, stringify, the default API, and an attempted maxDepth: 3000 bypass against 3,000 nested braces; each rejected safely. GitHub currently reports no checks for this branch. This is a promising fix for GHSA-vfj7-8cjw-p6xm; a published upstream release is still needed before downstream projects can replace source pins or clear their dependency audits.

KM-it-ops added a commit to KM-it-ops/Sniffoutpro that referenced this pull request Oct 10, 2026
…pm audit (#14)

braces <=3.0.3 has a high-severity stack-exhaustion DoS advisory with no
patched release (3.0.3 is latest; upstream fixes micromatch/braces#87 are
unmerged). It reaches us only through dev tooling (lint-staged, eslint via
micromatch/fast-glob), whose glob patterns come from repo config, not
untrusted input. Newest micromatch, fast-glob and eslint-plugin-boundaries
still require braces, so no upgrade clears it.

Ignore this one GHSA only; all other high/critical findings still fail CI.
Remove once braces publishes a fix.
Victorzinn704 added a commit to Victorzinn704/Desk-Imperial-Open-Source that referenced this pull request Oct 11, 2026
…es (#35)

Corrige dependências vulneráveis e incompatibilidades dos consumidores,
e acrescenta uma mitigação temporária verificável para `braces@3.0.3`. A
auditoria bruta permanece em **37 achados: 20 moderados e 17 altos**; a
auditoria de produção permanece em **zero**. Os 17 altos da cadeia de
desenvolvimento só recebem `PASS_WITH_VERIFIED_BACKPORT` quando todas as
provas passam. O advisory do GitHub continua visível; nome e versão do
pacote não são falsificados.

Closes #34
Relacionado a #32 e #33. A remoção/revisão do backport é acompanhada em
#36, que deve permanecer aberta.

### Dependências e compatibilidade

- Atualiza o lock sem `--force`/`--legacy-peer-deps`, preservando Prisma
6.19.3 e as ferramentas de análise. A auditoria anterior tinha 92
achados, incluindo 38 altos e 5 críticos.
- Atualiza OpenTelemetry 0.223/2.12 e adapta o processor de logs,
coberto por exportação HTTP real para coletor local. Convenções HTTP
estáveis podem exigir ajustes em dashboards externos que dependam dos
nomes antigos.
- Atualiza Sharp/PostCSS/Vite/protobufjs e restringe overrides de major
a `@prisma/config -> deepmerge-ts 8.0.2` e `@nestjs/swagger -> js-yaml
5.4.3`, com consumidores reais revisados. Remove `@swc/cli` sem uso pelo
build TSC.
- Corrige compatibilidade de tipos e três transições de estado React,
com cinco regressões incluindo SSR e NaN. Dez arquivos receberam apenas
ajustes do novo Prettier; o JavaScript emitido dos nove TS/TSX foi
comparado sem diferenças.
- Declara Node 22 em engines e `.nvmrc`; eleva os pisos diretos de Next
16.4.0, Vitest/coverage-v8 4.1.11 e PostCSS 8.5.29 às versões já
resolvidas, sem trocar entradas instaladas, tarballs ou SRI.

### Backport e controles

- Aplica somente cinco arquivos do delta de segurança do [PR upstream
#87](micromatch/braces#87), sobre o tarball
oficial 3.0.3. Não incorpora outras mudanças posteriores à release. A
licença MIT é preservada.
- Inventaria lock, workspaces, aliases e cópias físicas; confere os dez
arquivos originais, arquivos extras, integridades e árvores completas.
Recusa adulteração, patch parcial, cópia extra e escape por symlink.
Aplicação é idempotente; o gate verifica sem reparar.
- Preserva resultados brutos full/runtime, exit codes e stderr como
artefatos com upload `always()`. Confere advisory oficial, versão latest
do registry, lock revisado e regressões reais por cópia. Erro de rede,
mudança de advisory/fonte/lock, novo high/critical, runtime
high/critical, ausência de prova ou regressão falham.
- Mantém o nome obrigatório **Security Checks**, adicionando testes
adversariais e o wrapper. Mantém scanners consultivos;
`security:audit-runtime` executa audit estrito, substituindo a allowlist
histórica ampla.
- Instalação `--omit=dev` permite zero cópias exclusivamente dev; isso
não conta como prova do gate full. Prepare mantém Husky em
desenvolvimento e o dispensa quando omitido.
- Revisão técnica automatizada por Codex nesta sessão, dentro da
manutenção autorizada, sem alegar aprovação humana específica. Expira ao
fim de **10/11/2026 em Brasília: 11/11 às 00:00 BRT, 03:00 UTC**. Sem
renovação automática; instalação também falha após o prazo. Ver [decisão
e
limites](https://github.com/Victorzinn704/Desk-Imperial-Open-Source/blob/6379d8b4cdfbc50d21434519e4b829ab36a34608/docs/security/braces-backport-2026-10-11.md).

### Validação desta integração

Windows, **Node 22.23.3**:

- `npm ci`: 1.713 pacotes, cerca de 2 minutos; postinstall aplicou e
verificou a cópia. Após alinhamento dos pisos, aplicação idempotente
passou no lock revisado.
- `npm ci --omit=dev`, em exportação isolada do índice: 708 pacotes,
140,66 s, zero cópias de braces; prepare passou com HUSKY não definido.
- Prisma Client 6.19.3 gerado; 149/149 testes de
integridade/política/runner passaram. O experimento isolado do backport
passou 778 testes e comparou 383 casos, com 108 padrões ordinários
idênticos antes/depois.
- Gate real, com GitHub e registry consultados: passou em 20,37 s; raw
37, mitigados 17, runtime 0; 104 assertivas reais na cópia instalada,
com verificação antes/depois e relatórios originais preservados.
- API completa: 84 suítes, 904 testes passaram e 1 skipped; inclui o
coletor OTLP real. A primeira execução concorrente teve timeout OTLP e
duas falhas de espera na interface; a API completa e os 10 testes do
arquivo de interface passaram isolados, sem mudar timeouts ou código de
produto.
- Web completa com `--maxWorkers=2`: 128 arquivos, 896 testes passaram.
A repetição com workers padrão teve 895/896; o mesmo arquivo passou
10/10 isolado. O comando original da CI foi preservado, sem aumentar
timeouts ou alterar testes.
- Gulp real leu e filtrou uma fixture com glob de chaves, comparando
nomes e conteúdos. Knip passou; jscpd analisou 602 arquivos, com 1,79%
de linhas duplicadas abaixo do limite de 3%. Para contornar a resolução
de separadores do jscpd no Windows, os mesmos seis caminhos da
configuração foram passados como argumentos relativos.
- Scan público passou para 1.674 arquivos. Prettier passou na exportação
do índice com LF; o checkout Windows com CRLF mantém diferenças locais
de fim de linha. Hooks normais de commit passaram: Gitleaks e Prettier
executaram; Biome/ESLint não tiveram TS/TSX nestes commits.
- O helper de bindings nativos deixou de executar `npm install
--no-save`, que reorganizava a árvore fora do lock. Agora confere
caminhos reais, entradas/versões do lock e resolução pelo parent antes
de carregar o binding; ausência ou incompatibilidade falham. Nove testes
externos de fixtures passaram, incluindo versão nested vs raiz, falta,
identidade, lock divergente e escapes; o carregamento dos binários GNU
reais depende do CI Linux desta revisão.
- Build API (`build:verify`, incluindo validação Prisma) e build de
produção Next 16.4.0 passaram com Node 22.23.3. Foram usadas URLs locais
de teste para DATABASE/DIRECT/API; nenhum deploy foi executado. O
arquivo `next-env.d.ts` regenerado foi restaurado, preservando o diff
revisado.

No [CI Linux do head
`486507678f8702bc646250426dd6e5c6dda13779`](https://github.com/Victorzinn704/Desk-Imperial-Open-Source/actions/runs/38160165833),
**Frontend Unit Tests, Backend Tests, Quality (Lint + Typecheck) e
Security Checks passaram**; os demais checks ainda precisam concluir. O
teste web da CI usou seu comando original. Na rodada imediatamente
anterior (`6379d8b`), Security Checks passou, mas sete jobs consumidores
foram bloqueados pela verificação que detectou o helper antigo movendo
uma binding para um caminho não registrado no lock. Esse helper foi
corrigido no novo head; não foi relaxado o guard. O PR permanece
**draft**, sem merge ou deployment.

Limites: o patch limita profundidade de padrões/ASTs do parser e ciclos
percorridos; não promete resolver expansão cartesiana nem objetos
JavaScript arbitrários. O inventário prova pacotes npm identificáveis,
não código copiado e renomeado como aplicação. Requer instalação
exclusiva, sem escritores concorrentes. [Advisory ainda
aberto](GHSA-vfj7-8cjw-p6xm).
@ahmed-anis-rowaished

Copy link
Copy Markdown

Independent security and regression evaluation

I independently evaluated this PR at commit d44b9b1ee12e7804d4232d5a47a4a0c61d2fbefe against the stack-exhaustion issue tracked as GHSA-vfj7-8cjw-p6xm / CVE-2026-93687.

Verification summary:

  • Confirmed that published braces 3.0.3 and current unpatched master can terminate with RangeError: Maximum call stack size exceeded when processing deeply nested but size-bounded input.
  • Executed the reproduction in an isolated child process with a five-second timeout and restricted stack size.
  • Verified the candidate across braces(), compile(), expand(), stringify(), caller-provided deep ASTs, and cyclic parent references.
  • The candidate rejected excessive depth deterministically with controlled errors instead of exhausting the call stack.
  • Full upstream suite: 908 passed, 0 failed.
  • Valid brace expansion regression cases remained equivalent to braces 3.0.3.
  • git diff --check passed.
  • No dependency, installation-script, workflow, binary, or unrelated supply-chain changes were observed in the reviewed diff.
  • A normal-input benchmark of 10,000 iterations completed in approximately 118.59 ms, compared with approximately 103.89 ms on the unpatched baseline in the same environment.

The most important property of this approach is that it protects every recursive AST traversal, including externally supplied ASTs and cyclic parent references, rather than guarding only the parser.

Environment used for this independent check: Windows_NT 10.0.26200 (x64), Node.js v24.19.0, npm 11.17.0.

This is an independent engineering review, not a formal security audit. Based on the tested commit, the patch appears suitable for maintainer review and a patched npm release. Publishing an official release and updating the GitHub advisory’s patched-version metadata would unblock downstream consumers that cannot safely use forks, overrides, or unpublished commits.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants