Repository navigation
ci: Markdown Lint fails repo-wide on a braces advisory with no patched release (GHSA-vfj7-8cjw-p6xm) #540
Description
Summary
Markdown Quality → Markdown Lint fails on main and on every PR as it re-runs. The failure is in the Install linter dependencies step, before markdownlint executes — so it is not a lint error in any file.
5 high severity vulnerabilities
braces vulnerable to stack-exhaustion denial of service through deeply nested patterns
— GHSA-vfj7-8cjw-p6xm
braces → micromatch → fast-glob → globby → markdownlint-cli2
##[error]Process completed with exit code 1
The step is npm ci && npm audit --audit-level=high (.github/workflows/markdown-quality.yml:43-47). npm ci succeeds; npm audit exits 1.
Not caused by any change
GHSA-vfj7-8cjw-p6xm was published between 2026-10-02 and 2026-10-03. Nothing in the repo moved.
main @ 3634046 failure 2026-10-03T14:17:50Z ← current main
main @ 410f332 success 2026-10-02T23:47:08Z
main @ 13d9d3a success 2026-10-02T22:18:19Z
Open PRs still showing pass are displaying cached runs from before the advisory. They will fail on their next run. Every PR is affected as soon as CI re-triggers.
npm audit fix does not fix it
npm reports fixAvailable: markdownlint-cli2@0.23.3 (isSemVerMajor: true). That is wrong — I installed it in a scratch directory and re-audited:
$ npm i --save-exact markdownlint-cli2@0.23.3
$ npm audit --audit-level=high
STILL FAILS (exit 1)
braces present: 3.0.3
braces sev=high range=* direct=False
fast-glob sev=high range=* direct=False
globby sev=high range=>=8.0.0 direct=False
micromatch sev=high range=>=0.2.0 direct=False
markdownlint-cli2 sev=high range=>=0.0.5 direct=True
markdownlint-cli2@0.23.3 depends on globby@16.2.4 and micromatch@4.0.8, which still reach braces@3.0.3.
The advisory range for braces is * — every published version. Latest is 3.0.3 (published 2024-05-21); there is no patched release. So no dependency bump clears this gate, and taking the breaking major upgrade would be churn for no benefit.
Current pins (.github/linters/): markdownlint-cli2@0.22.1, braces@3.0.3, micromatch@4.0.8, globby@16.2.0, fast-glob@3.3.3.
Impact
Markdown Lint is not in the ruleset's required status checks (Conventional Commit Title, pre-commit, acq offline suite under bash 3.2), so it does not block merges. But:
- Every PR shows a red check that is nobody's fault, and reviewers have to be told to ignore it.
- A persistently-red non-required check trains people to ignore red checks, which is how a real failure gets waved through.
npm run lint:mdstill works locally — only the CI audit gate fails — so the signal loss is CI-only.
Options
- Scope the audit gate to what is actionable.
npm audit --audit-level=high --omit=dev, or drop the audit from this workflow and let the existing Dependabot/lint:secretspath own dependency alerting. The markdown workflow's job is linting markdown; a transitive DoS advisory in a dev-only glob library is not what it should gate on. - Allowlist this advisory explicitly (e.g.
npm audit --audit-level=high || truewith a documented exception, or anaudit-ci-style allowlist naming GHSA-vfj7-8cjw-p6xm) so the gate keeps working for everything else and the exception is visible and reviewable. - Accept the breaking bump to
markdownlint-cli2@0.23.3— does not help, per the test above. Listed only to rule it out.
Option 1 or 2. Worth noting this is the same class as e712685 ("pin markdownlint-cli2 once, clear GHSA-253c"), which cleared a different advisory the same way — a new advisory will re-break it again, so a durable policy beats another one-off pin.
Risk assessment for the allowlist path
braces is a dev-only transitive dependency of a markdown linter that runs on trusted repo content in CI. The advisory is a stack-exhaustion DoS triggered by deeply nested brace patterns. The inputs here are this repository's own .md file paths and the glob patterns in .markdownlint-cli2.yaml. There is no untrusted input path, and the blast radius of a successful exploit is a hung CI job.
Notes
Found while updating #519 from main — the merge was clean and all required checks pass, but Markdown Lint went red for this reason rather than anything in that branch.
Activity
mogul commentedon Oct 4, 2026
Additional context from #541:
<= 3.0.3, patched versionsNone; latestbracesis3.0.3, so no dependency bump ofbraces,micromatch,globby, ormarkdownlint-cli2can currently makenpm audit --audit-level=highpass.npm audit fix --forcemust not be used here: it attempts to installmarkdownlint-cli2@0.0.4, an ancient release that predates the current dependency chain and would gut linting rather than fixbraces.**/*.mdplus fixed ignores in.markdownlint-cli2.yaml), supplied by maintainers, not by an attacker. The practical impact is availability-only on a dev-time CI linter: a crashed linter is a failed check, not a confidentiality or integrity breach.--audit-level=critical.Markdown Qualityand let a dedicated dependency-audit path own dependency alerting.This is why #541 leaves
.github/linters/package.json,.github/linters/package-lock.json, and.github/workflows/markdown-quality.ymluntouched.mogul commentedon Oct 6, 2026
Resolved in #548