Skip to content

chore(deps): migrate to eslint 10 to clear the brace-expansion DoS advisory #1838

Closed

Description

@cliffhall

Deferred from the pre-2.0.0 dependency sweep (#1837). Dev-scope only — does not ship.

The alert

A brace-expansion DoS (unbounded expansion length) reachable via minimatch, inside eslint's own dependency tree. It appears 5 times in each of the 5 lockfiles (root + four clients) as:

  • @eslint/config-array
  • @eslint/eslintrc
  • brace-expansion
  • eslint
  • minimatch

npm audit reports a single fix for all of them: eslint@10.8.0.

Why it was deferred rather than fixed

  1. It does not ship. eslint is a dev dependency; the published files allowlist is clients/*/build, clients/web/dist, and scripts/install-clients.mjs.
  2. The vulnerable path is not attacker-controlled. The glob patterns fed to minimatch come from this repo's own eslint config. Worst case is a slow lint run on a machine that already has the source.
  3. The fix is a major bump across five packages, likely requiring flat-config and rule migrations — not work to attempt immediately before an irreversible npm publish.

The alerts were dismissed as tolerable_risk with that reasoning recorded. This issue exists so the dismissal is not the only record that real work remains — a dismissed alert reads too easily as a solved problem.

Scope

  • Bump eslint to 10.x in the root and all four clients (each has its own package.json / lockfile — v2 is not an npm workspace).
  • Migrate config as required; the root eslint.config.js also gates core/ and the shared surface (lint:core, lint:shared).
  • Verify npm run ci passes — lint runs in validate for every client.
  • Confirm the 25 alerts clear, and un-dismiss rather than leave them dismissed-but-fixed.

Related

Activity

  1. self-assigned this
    on Jul 28, 2026
  2. cliffhall commented on Jul 28, 2026

    @cliffhall
    MemberAuthor

    Confirmed by Dependabot: the automated bump cannot work unassisted.

    Dependabot opened #1840 attempting exactly this upgrade, and its build failed:

    npm error code ERESOLVE
    npm error ERESOLVE could not resolve
    npm error While resolving: eslint-plugin-react-hooks@7.0.1
    npm error Found: eslint@10.8.0
    npm error   dev eslint@"^10.8.0" from the root project
    

    Failed run

    So this is not a version-bump task. eslint-plugin-react-hooks@7.0.1 does not accept eslint 10, and the @typescript-eslint / typescript-eslint@8.57.0 stack sits in the same peer graph. The migration has to move the plugin set in lockstep with eslint itself.

    Adds a concrete first step to the scope above: audit every eslint plugin for eslint-10 support before touching eslint, and expect at least eslint-plugin-react-hooks and the typescript-eslint family to need coordinated major bumps.

    Also means #1840 should be closed rather than fixed — Dependabot will keep reopening it, and the work belongs here.

  3. cliffhall commented on Jul 28, 2026

    @cliffhall
    MemberAuthor

    Correction — the sweep in #1837 fixed most of this, and what remains is narrower and subtler than the issue body describes.

    There are four separate brace-expansion advisories, not one. The sweep (bumping the 1.x copy to 1.1.16) resolved three:

    Advisory Vulnerable range State after #1837
    GHSA-3jxr-9vmj-r5cp < 1.1.16 ✅ fixed (×8)
    GHSA-f886-m6hf-6m8v < 1.1.13 ✅ fixed (×2)
    GHSA-jxxr-4gwj-5jf2 >= 5.0.0, < 5.0.6 ✅ fixed (×1)
    GHSA-mh99-v99m-4gvg <= 5.0.7 ⚠️ auto-dismissed (×5)

    Only GHSA-mh99-v99m-4gvg remains, and it is the awkward one: its vulnerable range <= 5.0.7 carries no lower bound, so brace-expansion@1.1.16 is still inside it. The only patched version is 5.0.8, which the 1.x line will never reach — so no amount of updating within eslint's existing tree fixes it. Only moving eslint to a version whose dependency graph pulls brace-expansion 5.x does.

    This also explains an apparent tool disagreement worth recording, since it will confuse the next person:

    • GitHub Dependabot auto-dismissed the 5 remaining alerts at 2026-07-28T03:25:29Z under its low-impact dev-dependency rule, so they no longer appear in the open list.
    • npm audit has no such rule and still reports eslint, @eslint/config-array, minimatch, brace-expansion as high, naming eslint@10.8.0 as the fix.

    Neither is wrong. They are measuring different things: Dependabot filtered by impact, npm audit did not.

    Net effect on this issue: still valid, but the driver is now "npm audit is not clean" rather than "there are open Dependabot alerts" — GitHub has already dismissed those itself. That lowers the urgency further, and means no manual dismissal is needed for the eslint cluster; it is already handled.

    The blocker remains as recorded in the previous comment: eslint-plugin-react-hooks@7.0.1 does not accept eslint 10 (proven by Dependabot's own failed attempt in #1840), so the plugin set has to move in lockstep.

  4. added this to the v2.1.0 milestone on Jul 28, 2026
  5. removed their assignment
    on Jul 29, 2026
  6. cliffhall commented on Aug 1, 2026

    @cliffhall
    MemberAuthor

    Triage: Priority = Medium

    Scored 7/16 with the priority rubric added to AGENTS.md in #1891. This card is already approved and sitting in Todo — only Priority was set here, its Status is unchanged.

    Axis Score Reasoning
    Severity / impact 2/5 A brace-expansion DoS reachable through eslint's own dependency tree. Dev-scope only, does not ship, and the practical impact is npm audit noise across five lockfiles rather than a reachable attack on anyone.
    Urgency / staleness 4/5 v2.1.0 milestone, due 2026-08-05, and open advisories are conspicuous at release time.
    Signal bonuses +1 milestone (v2.1.0) (+1)
    Total 7 Lands in the Medium band (6-8).

    Related issues. One connected issue:

    Scores are a starting point, not a verdict — the rubric is meant to be overruled when it's plainly wrong, provided the reason is written down.

  7. self-assigned this
    on Aug 1, 2026
  8. cliffhall commented on Aug 2, 2026

    @cliffhall
    MemberAuthor

    Closed by #1900, squash-merged into v2/main as 834fd2d7. (Auto-close doesn't fire here — Closes #N only closes on PRs targeting the default branch, and v2 PRs target v2/main.)

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

Metadata

Metadata

Assignees

Labels

v2Issues and PRs for v2

Type

No type

Projects

No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions