Skip to content

fix(deps): patch brace-expansion and js-yaml DoS advisories in TS SDK dev tree#141

Open
adnanrhussain wants to merge 2 commits into
mainfrom
ahussain/dependabot-brace-expansion-js-yaml
Open

fix(deps): patch brace-expansion and js-yaml DoS advisories in TS SDK dev tree#141
adnanrhussain wants to merge 2 commits into
mainfrom
ahussain/dependabot-brace-expansion-js-yaml

Conversation

@adnanrhussain

@adnanrhussain adnanrhussain commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Resolves Dependabot alerts #25, #26, #27 (all High).

The advisories

GHSA-3jxr-9vmj-r5cpbrace-expansion (alerts #25, #26), CVE-2026-13149

expand_() computes post by recursing over the entire remaining input before the early-return branches that discard it. For input made of consecutive non-expanding {} groups, every level spawns two recursions over the same tail — T(n) = 2·T(n−1), i.e. O(2ⁿ). A ~90-byte / 30-group input blocks the calling thread for ~2 minutes; slightly longer hangs it indefinitely. The max option does not help — it only bounds the output-building loops, not either recursion. Reachable transitively through any minimatch/glob brace pattern.

GHSA-52cp-r559-cp3mjs-yaml (alert #27), CVE-2026-59869

A chain of mappings where each merges the previous (a1: &a1 { <<: *a0, ... }) forces the loader to re-enumerate inherited keys at every link: 1 + 2 + … + N merged-key visits, so O(N²) CPU for O(N) input. At N=4000 (<100 KB of YAML) parse time exceeds 1s and grows quadratically from there.

Both are CPU-exhaustion / DoS classes — no data exposure, no code execution.

Do they need fixing?

Not exploitable as we use them, but worth patching. All three are devDependencies, transitive, and confined to sdks/typescript/package-lock.json:

Package Version Reached via When it runs
brace-expansion 5.0.6 eslint / @typescript-eslint/typescript-estreeminimatch npm run lint
brace-expansion 2.1.1 openapi-typescript@redocly/openapi-coreminimatch npm run generate:kg-types
js-yaml 4.2.0 openapi-typescript@redocly/openapi-core npm run generate:kg-types

Why the practical risk is low:

  • No runtime exposure. tsup does not bundle either package into dist/ (verified — no references in the build output), and neither appears in dependencies or peerDependencies. SDK consumers installing @learning-commons/evaluators never resolve them.
  • No attacker-controlled input. The brace-expansion inputs are our own ESLint glob patterns and in-repo file paths. The js-yaml input is a single first-party document, https://docs.learningcommons.org/api-reference/knowledge-graph-api/openapi.yaml.
  • No CI reachability for the codegen path. generate:kg-types is not invoked by any workflow; it is a manual, developer-run script.
  • Worst realistic outcome is a slow build on a developer machine, not a service outage.

So: not urgent, not a live vulnerability for this repo. We're fixing it anyway because the change is dev-tree-only, behaviour-preserving, and leaving three High alerts open makes real alerts harder to spot.

How this fixes it

  • brace-expansion → 5.0.8 and 2.1.2 (patched at 5.0.7 / 2.1.2) via npm audit fix. Both requirers use caret ranges (^5.0.5, ^2.0.1), so this is a lockfile-only bump with no manifest change. The upstream fix defers computing post until after the early-return branches, and converts the {a},b} rewrite from recursion to an in-function loop.

  • js-yaml → 4.3.0 (first patched version) via a scoped overrides entry in package.json. @redocly/openapi-core@1.34.16 pins js-yaml to an exact 4.2.0, and openapi-typescript@7.13.0 — the current latest — pins @redocly/openapi-core: ^1.34.6, so there is no upstream release to upgrade into. The override is deliberately scoped to @redocly/openapi-core rather than applied tree-wide:

    "overrides": {
      "@redocly/openapi-core": {
        "js-yaml": "4.3.0"
      }
    }

    The version is pinned exactly rather than caretted. @redocly/openapi-core deliberately pins js-yaml to an exact 4.2.0; a caret override would replace that pin with a floating range and let future 4.x minors drift into the one dependency this override exists to control. An exact pin holds the security floor and routes any further movement through Dependabot.

    The upstream fix caps total merged keys per parse (default 10K), which closes this and related merge edge cases. Our only js-yaml consumer parses one small first-party OpenAPI document, well under that cap.

    This override should be removed once openapi-typescript ships a release depending on @redocly/openapi-core 2.x (which already uses js-yaml@^5.2.1).

Also picked up incidentally by npm audit fix: tsx's nested esbuild 0.28.0 → 0.28.1. No other resolved versions changed.

Lockfile regenerated on Linux

The lockfile is regenerated in a node:24 container rather than on macOS. npm only writes the libc filter arrays (["glibc"] / ["musl"]) for platform-specific optional deps when it resolves on Linux, so regenerating on macOS silently drops them from 10 packages — @rolldown/binding-linux-* and lightningcss-linux-*. main's lockfile was last written by Dependabot (#136), which runs on Linux, so a macOS regeneration would have deleted that metadata and the next Dependabot PR would have re-added it, flip-flopping the diff indefinitely. This is platform-driven, not npm-version-driven: npm 10.9.4 and 11.6.2 both drop the fields on darwin even from a clean slate with correct registry metadata.

Regenerating under Linux keeps all 10 libc arrays intact and confines the diff to the intended version bumps — 117 insertions / 117 deletions, all pure replacements.

npm audit now reports 0 high, 0 moderate. One Low remains — GHSA-g7r4-m6w7-qqqr, top-level esbuild, arbitrary file read via the dev server on Windows. It is out of scope for these three alerts, requires a breaking upgrade, and we do not run the esbuild dev server; leaving it for a separate change.

Verification

  • npm audit — 3 High resolved; only the unrelated Low remains

  • npm run test:unit — 318/318 pass (22 files)

  • npm run lint — 0 errors

  • npm run typecheck — clean

  • npm run build — succeeds

  • js-yaml behaviour equivalence: ran generate:kg-types under js-yaml 4.2.0 and 4.3.0 against the same spec URL and diffed the outputs — byte-identical. (The generated kg-api.d.ts does drift against main, but that is upstream OpenAPI spec drift unrelated to this bump; it is deliberately not included here.)

  • libc metadata: all 10 libc arrays preserved; the only resolved-version changes vs main are the three intended bumps plus tsx's nested esbuild

  • Override is honoured: there is no package.json or workspace root above sdks/typescript, so overrides applies. (In a non-root workspace package npm would ignore it silently.)

demos/typescript/package-lock.json resolves neither package, so no change is needed there.

Follow-ups (not blocking)

  • Remove the overrides entry once openapi-typescript ships a release depending on @redocly/openapi-core 2.x, which already uses js-yaml@^5.2.1. Left in place, the override would eventually pin js-yaml down against what redocly actually wants and mask a legitimate resolution.
  • Consider pinning packageManager in package.json, so lockfile regeneration is reproducible regardless of who runs it and on what platform.
  • Top-level esbuild Low (GHSA-g7r4-m6w7-qqqr) still needs a breaking upgrade; out of scope here.

@codecov

codecov Bot commented Jul 24, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Updates the TypeScript SDK’s dev dependency tree to remediate three high-severity Dependabot advisories (brace-expansion and js-yaml DoS), primarily via lockfile bumps plus a targeted npm overrides pin for a transitive constraint in @redocly/openapi-core.

Changes:

  • Add a scoped overrides rule to force @redocly/openapi-core to use js-yaml@^4.3.0.
  • Update resolved versions in package-lock.json for brace-expansion (2.1.2, 5.0.8) and js-yaml (4.3.0), plus an incidental nested esbuild patch bump under tsx.

Reviewed changes

Copilot reviewed 1 out of 2 changed files in this pull request and generated no comments.

File Description
sdks/typescript/package.json Adds a scoped npm override to lift js-yaml for @redocly/openapi-core to a patched version.
sdks/typescript/package-lock.json Locks patched versions of brace-expansion and js-yaml (and an incidental esbuild patch) in the TypeScript SDK dev dependency tree.
Files not reviewed (1)
  • sdks/typescript/package-lock.json: Generated file

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@czi-fsisenda czi-fsisenda left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

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