Skip to content

fix(deps): replace braces with depth-guarded local shim (Dependabot #200) - #118

Merged
marc-aurele-besner merged 1 commit into
mainfrom
fix/dependabot-200-braces-shim
Oct 9, 2026
Merged

marc-aurele-besner merged 1 commit into
mainfrom
fix/dependabot-200-braces-shim

Conversation

@marc-aurele-besner

Copy link
Copy Markdown
Owner

What this does

Resolves Dependabot alert #200 (braces — GHSA-vfj7-8cjw-p6xm / CVE-2026-93687) by removing the vulnerable braces@3.0.3 from package-lock.json.

Why a local shim

braces@3.0.3 is the latest release on npm and the upstream maintainer disputes the report, so no patched version is installable. react-scripts is end-of-life and its transitive chain (react-scripts → eslint-webpack-plugin → micromatch@4.0.8 → braces@3.0.3) hard-pins ^3.0.3, so bumping parents does not close the chain either.

The previous fix (merged in PR #114) documented the exposure but the alert stayed open because Dependabot auto-resolves only when the vulnerable version leaves the lockfile.

Approach

tools/braces-shim/ is an npm workspace package (name braces, version 3.0.4) carrying the v3.0.3 source with a recursion-depth guard layered on top:

  • new MAX_AST_DEPTH: 100 constant
  • new assertDepth(depth) helper that throws a SyntaxError past the limit
  • parse calls assertDepth(stack.length) whenever it pushes a ( or { frame
  • compile, expand, and stringify thread a depth counter through their recursive walkers and assert at the top of each recursion

The public API (braces, braces.parse, braces.stringify, braces.compile, braces.expand, braces.create) is unchanged, so the only two in-tree callers — micromatch (via eslint-webpack-plugin) and chokidar (via tailwindcss) — resolve to the shim without modification.

With the workspaces entry in package.json, node_modules/braces is hoisted as a single symlink and both transitive chains dedupe to it. package-lock.json no longer contains any braces@<=3.0.3 entry, so Dependabot can auto-resolve alert #200 on merge. Verified by npm audit --json | jq '.vulnerabilities.braces' returning null.

The depth-guard technique is the smallest version of the upstream PR stack (#78, #79, #82, #87) that actually closes the CVE — a literal-collapse rewrite would be more invasive than this project needs.

Verification

Check Result
npm ls braces single braces@3.0.4 -> ./tools/braces-shim, both micromatch and chokidar dedupe to it
npm audit no braces / GHSA-vfj7 entry
grep "node_modules/.*braces" package-lock.json exactly one entry, node_modules/braces → tools/braces-shim (link)
require('braces/package.json').version in a fresh shell 3.0.4
braces('{a,b,c}') / braces('foo/{a,b}/bar', {compile: true}) / braces.expand('{1..5}') unchanged behavior
200-level deeply nested pattern throws SyntaxError: AST nesting depth exceeds the maximum of 100 (instead of stack overflow)
CI=true npm run build Compiled successfully (283 kB main bundle)
CI=true npm test project has no test files (same as on main)

No GitHub Actions workflows are configured for this repo, so there is no CI to watch.

How to remove this

Delete tools/braces-shim/, drop the workspaces entry from package.json, and revert SECURITY.md whenever one of the following lands:

  1. braces ships a patched release on npm.
  2. The project migrates off react-scripts (CRA) to an actively maintained bundler (Vite, Next.js, etc.).

SECURITY.md records the same removal procedure.

…SA-vfj7-8cjw-p6xm

braces@3.0.3 is the latest release on npm and the upstream maintainer
disputes the report, so no patched version is installable. Since
react-scripts is end-of-life, bumping parents does not drop braces from
the tree either. Documenting the exposure in SECURITY.md was not enough
to close the Dependabot alert, which tracks the presence of vulnerable
versions in package-lock.json.

Add tools/braces-shim, a workspace package name=braces version=3.0.4
that re-implements the v3.0.3 source with a recursion-depth guard: a
MAX_AST_DEPTH=100 constant plus an assertDepth helper called whenever
parse pushes a new brace/paren frame and threaded through the recursive
walkers in compile/expand/stringify. The public API (default export plus
.parse/.stringify/.compile/.expand/.create) is unchanged, so callers
(micromatch, chokidar) keep working untouched.

node_modules/braces is hoisted as a single symlink to the shim, so both
transitive chains (eslint-webpack-plugin -> micromatch, and
tailwindcss -> chokidar) dedupe to the patched version and no
<= 3.0.3 entry remains in package-lock.json. npm audit no longer flags
the advisory and react-scripts build still compiles successfully.

Delete tools/braces-shim/, drop the workspace entry, and revert
SECURITY.md once braces ships a patched release upstream (or the
project migrates off react-scripts).

- fixes Dependabot alert #200
@netlify

netlify Bot commented Oct 9, 2026 •

Copy link
Copy Markdown

✅ Deploy Preview for legacy-golfalpine ready!

Name Link
🔨 Latest commit 91765cc
🔍 Latest deploy log https://app.netlify.com/projects/legacy-golfalpine/deploys/6ac8d0027ca32e000910eb12
😎 Deploy Preview https://deploy-preview-118--legacy-golfalpine.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@marc-aurele-besner
marc-aurele-besner merged commit 7108a76 into main Oct 9, 2026
4 checks passed
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.

1 participant