Skip to content

fix(security): resolve open dependency alerts; harden git_add#4376

Merged
cliffhall merged 1 commit into
modelcontextprotocol:mainfrom
olaservo:fix/server-vulns-2026-06
Jun 16, 2026
Merged

fix(security): resolve open dependency alerts; harden git_add#4376
cliffhall merged 1 commit into
modelcontextprotocol:mainfrom
olaservo:fix/server-vulns-2026-06

Conversation

@olaservo

Copy link
Copy Markdown
Member

Summary

Resolves the open dependency security alerts across the monorepo and adds defense-in-depth to the git server's git_add.

Dependency updates

  • Python (git, fetch, time uv.lock): idna 3.10 → 3.18 (GHSA-65pc-fj4g-8rjx), starlette 0.49.1 → 1.3.1 (GHSA-86qp-5c8j-p5mr).
  • npm: vitest 2.1.8 → 4.1.8 in the four TS servers (GHSA-5xrq-8626-4rwp, critical). vitest 4 brings vite 8 (rolldown, no esbuild), which clears the esbuild/vite alerts without overrides. Root overrides added for qs >=6.15.2 (GHSA-q8mj-m7cp-5q26, pulled via express) and hono >=4.12.21 (multiple advisories, pulled via @modelcontextprotocol/sdk).

git_add hardening (defense-in-depth)

git_add already rejects out-of-tree paths because it shells out via repo.git.add (the fix from #3164), rather than repo.index.add. This adds an explicit path-boundary check before the git call plus regression tests asserting the security invariant — out-of-tree paths are never staged — to guard against a future regression back to repo.index.add (CVE-2026-27735).

Verification

  • npm audit: 0 vulnerabilities
  • TS: 313 tests pass (everything 107, filesystem 147, memory 45, sequentialthinking 14); all builds pass.
  • Python: git / fetch / time test suites pass under the updated dependencies.

🤖 Generated with Claude Code

Real fixes (deps):
- python (git/fetch/time): idna 3.10->3.18 (GHSA-65pc), starlette
  0.49.1->1.3.1 (GHSA-86qp)
- npm: vitest ^2.1.8->^4.1.8 (critical GHSA-5xrq UI server RCE). vitest 4
  pulls vite 8 (rolldown, no esbuild), clearing the esbuild/vite advisories
  natively. Remaining root overrides: qs>=6.15.2 (GHSA-q8mj, via express),
  hono>=4.12.21 (via @modelcontextprotocol/sdk).
- npm audit: 0 vulnerabilities; all TS (313) + Python (git/fetch/time) suites
  and TS builds pass.

Hardening (git_add):
- The repo already mitigates CVE-2026-27735 by using repo.git.add (the git
  CLI rejects out-of-tree paths, PR modelcontextprotocol#3164's fix), not repo.index.add (which
  did not). Add an explicit path-boundary check in git_add as defense in
  depth plus regression tests asserting the security invariant (out-of-tree
  paths are never staged), guarding against a regression to repo.index.add.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@claude

claude Bot commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

Claude finished @cliffhall's task in 1m 45s —— View job


Review: dependency alerts + git_add hardening

  • Gather context (diff, changed files)
  • Review git_add hardening + tests
  • Review dependency updates (npm + Python)
  • Post review feedback

Overall this is a clean, well-scoped security PR. The git_add change is correct, the framing as defense-in-depth (the real fix — repo.git.add over repo.index.add from #3164 — is already in place) is accurate, and the tests assert the property rather than the layer. CI is green for both the Python and TypeScript matrices. Recommend merge after considering the minor notes below — none are blocking.


git_add hardening — src/git/src/mcp_server_git/server.py:136-152

The boundary check is correct:

  • repo_root / f correctly handles absolute paths (pathlib discards the left operand when the right is absolute), so an absolute path outside the tree is caught by relative_to. ✅
  • Non-existent paths are fine — Path.resolve() is non-strict by default, so traversal is rejected before the file needs to exist. ✅
  • Wrapping resolve() in except (OSError, RuntimeError) covers symlink loops / overly-long paths gracefully. ✅

Two things worth noting (neither blocking):

  1. Symlink behavior change. .resolve() follows symlinks, so a legitimately tracked symlink inside the repo whose target points outside the working tree would now be rejected with ValueError, whereas plain git add would have staged the link itself. This is an acceptable security trade-off, but it is a subtle behavior change for repos that track such symlinks. If you want to preserve that case, resolving the parent dir and re-appending the leaf name avoids dereferencing the leaf symlink. Mentioning for awareness only.

  2. ["."] branch is unvalidated (server.py:133-134) — correct and intentional (. is the repo root), just calling it out so it's a conscious choice rather than an oversight.

The two new tests (test_git_add_rejects_path_traversal, test_git_add_rejects_absolute_path_outside) are solid — accepting either ValueError or git.GitCommandError means they keep guarding the invariant even if the implementation layer shifts. Good regression coverage against a reintroduction of CVE-2026-27735.


Dependency updates

  • Python locks (idna 3.10→3.18, starlette 0.49.1→1.3.1): the starlette bump is a major version jump (0.x → 1.x) and is the highest-risk change in this PR, since the fetch server uses it (transitively via mcp 1.23.0 → sse-starlette / starlette) for the HTTP/SSE transport. The Python CI matrix passed, which is reassuring — just confirm the HTTP transport path is actually exercised by those tests rather than only stdio. The locks resolve consistently (CI uses uv sync --frozen, which would have failed on a hand-edited/out-of-sync lock).
  • npm (vitest 2.1.8 → 4.1.8, skipping major v3): large package-lock.json churn is expected here — vitest 4 pulls vite 8 (rolldown, no esbuild), which is what clears the esbuild/vite advisories without overrides. dev-dependency only, so no runtime/published-artifact impact. TypeScript CI green. ✅
  • Root overrides for qs >=6.15.2 and hono >=4.12.21 are reasonable as security floors (>= keeps them from pinning stale versions later). Worth a periodic check that these can be dropped once the upstream express / @modelcontextprotocol/sdk deps ship fixed versions transitively.

Trivial

  • src/memory/package.json and src/sequentialthinking/package.json end with no trailing newline. Likely pre-existing, but since both files were touched here it'd be a cheap cleanup.

@cliffhall

Copy link
Copy Markdown
Member

Review: supply-chain & breaking-change analysis

Reviewed the dependency changes against published advisories and the new versions' release notes. Adding two analysis sections plus a merge recommendation. Bottom line up front: every change maps to a real advisory, each floor/version is the correct one, and the practical breaking-change risk is verified-nil for this codebase — approve.

1. Supply-chain vulnerability assessment

Dependency Change Advisory it closes Severity Fixed in Resolves?
vitest (dev) 2.1.8 → 4.1.8 GHSA-5xrq-8626-4rwp / CVE-2026-47429 — UI server arbitrary file read→exec (RCE) Critical (9.8) 3.2.6 / 4.1.0 ✅ 4.1.8 ≥ 4.1.0
qs (override, via express) floor >=6.15.2 GHSA-q8mj-m7cp-5q26 / CVE-2026-8723stringify DoS; also subsumes GHSA-w7fw-mjwx-w883 (arrayLimit) Moderate (6.3) 6.15.2 ✅ floor is exact
hono (override, via MCP SDK) floor >=4.12.21 GHSA-xrhx-7g5j-rcj5 / CVE-2026-47674 — ip-restriction IPv6 bypass Moderate (5.3) 4.12.21 ✅ floor is exact
idna (transitive) 3.10 → 3.18 GHSA-65pc-fj4g-8rjx / CVE-2026-45409idna.encode() quadratic DoS (CVE-2024-3651 bypass) Moderate (6.9) 3.15 ✅ 3.18 ≥ 3.15
starlette (transitive) 0.49.1 → 1.3.1 GHSA-86qp-5c8j-p5mr / CVE-2026-48710 "BADHOST" — missing Host-header validation → path-check bypass Moderate (6.5) 1.0.1 ✅ 1.3.1 ≥ 1.0.1

Maturity of the new versions

  • vitest 4 → vite 8 / Rolldown is the largest new-code surface: vitest 4 pulls Vite 8, which swaps esbuild for the Rust Rolldown bundler. As of mid-2026 this is GA, not experimental (Vite 8 stable Mar 2026; Rolldown 1.0 production-ready May 2026). Since vitest is a devDependency, none of it enters the published packages' runtime footprint — blast radius is limited to CI/test.
  • qs / hono floors are the minimal correct ones on tiny, well-maintained libraries and subsume adjacent advisories — negligible added risk.
  • idna / starlette are reputable, actively maintained transitive deps; no yanked releases in the target lines, both at current latest.
  • No Python-floor regression: idna 3.18 raises its own floor to 3.9 and starlette 1.x stays at 3.10 — both ≤ the repo's >=3.10. ✅

Net: every change maps to a real, published advisory and each new version/floor genuinely closes it. npm audit: 0 and the passing suites corroborate. No typosquat / unexpected-transitive concerns surfaced.

2. Breaking changes & reported problems

vitest 2 → 4 (two majors). Real config-level breaking changes exist, but this repo dodges all of them — the four vitest.config.ts files use only globals / environment / include / coverage.provider:'v8', none of the removed APIs:

  • Removed/renamed: poolOptions, singleThread/singleForkmaxWorkers; defineWorkspacetest.projects; coverage.all; environmentMatchGlobs/poolMatchGlobs; top-level deps.*server.deps.*. None present here.
  • Engine floors: Vitest 4 needs Node ≥ 20 (repo is Node 22 ✅) and Vite ≥ 6.
  • coverage-v8 now uses AST-based remapping — coverage numbers may shift slightly vs v2 (cosmetic).
  • Reported v4.1.x issues are niche, not critical (Yarn-PnP + Vite 8 hang #9799; single-worker perf regression #8808) — neither applies to this setup.

starlette 0.49 → 1.3 (crosses 1.0). Breaking changes are concentrated at 1.0.0 and are removals of long-deprecated APIs: on_startup/on_shutdown (→ lifespan only), decorator routing (@app.route, @app.exception_handler, add_event_handler), FileResponse(method=...), import-time jinja2 requirement. These servers consume Starlette only transitively via the MCP SDK (stdio by default; Streamable HTTP optional) and author no Starlette app code, so the removed APIs don't touch repo code. uv already resolved the lock to 1.3.1, confirming the pinned SDK permits starlette 1.x. No yanked releases in 1.0–1.3.1.

idna 3.11 → 3.18. Unicode 16 (3.11), Py2 cleanup (3.12), Py≥3.9 floor (3.16), additive display arg (3.18). No behavioral break relevant to transitive requests/httpx usage.

qs / hono. Patch-level within their lines — no breaking changes.

3. Recommendation — approve & merge

No item warrants a more conservative pin:

  • Minimal-floor items are already minimal & correctqs >=6.15.2, hono >=4.12.21, idna ≥3.15 (taken to current 3.18). No "better version to pin" exists; these are exactly the patched floors.
  • The two larger jumps are unavoidable, not over-shooting:
    • starlette — there is no patched 0.49.x backport; CVE-2026-48710 is only fixed on the 1.x line (≥1.0.1), so crossing to 1.x is required to remediate. 1.3.1 is a fine target (latest patch, no yanks, no Python-floor change, no repo-facing API use).
    • vitest — the strict-minimum fix for the critical CVE is 3.2.6, so v4.1.8 exceeds what the CVE alone demands. It's still safe here (dev-only, configs use no removed APIs, suite passes) and standardizing on v4 is reasonable. If the smallest possible bump is preferred, vitest@^3.2.6 would also close GHSA-5xrq-8626-4rwp — but there's no correctness reason to prefer it given the configs are already v4-clean.

Two minor, non-blocking notes:

  1. PR wording on CVE-2026-27735. That CVE is an advisory against mcp-server-git itself (path traversal in git_add, remediated by the earlier switch to repo.git.add() in Add Path validation #3164) — not a GitPython CVE. The current text reads as if it were a GitPython issue; rewording would avoid sending reviewers to look for a GitPython bump. The added boundary check is sound defense-in-depth against a regression back to repo.index.add(), and the two regression tests correctly assert the property (reject from either ValueError or GitCommandError) rather than the layer. 👍
  2. Adjacent (out of scope): gitpython resolves at 3.1.45. A separate advisory (CVE-2026-44243, reference-creation APIs) is fixed in 3.1.48 — it does not affect git_add or any path this server uses, so not a blocker here, but a future gitpython>=3.1.48 bump would clear it.

🤖 Generated with Claude Code

@cliffhall cliffhall left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM! 👍

@cliffhall cliffhall merged commit a96189b into modelcontextprotocol:main Jun 16, 2026
19 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.

2 participants