Skip to content

Security audit - 2026-07-27

  • Reviewer: discord-mcp maintainers
  • Scope: dependency advisories only. The manual code review shipped as part of the v0.13.0 correctness audit (token redaction, untrusted-wrap completeness, confirmation gates, audit redaction) is not re-litigated here.
  • Supersedes: Security audit - 2026-05-01, whose “1 site-only moderate” figure was accurate on that date and had gone three months stale by this one.
Terminal window
pnpm audit --audit-level=high --prod # exit 0
SeverityCount in the production tree
critical0
high0
moderate1
low0
total1

Before v0.13.0 this command reported 27 high advisories and exited 1.

The single remaining moderate is a path-traversal advisory in @hono/node-server, reached via @modelcontextprotocol/sdk. It belongs to the SDK’s Streamable-HTTP transport, which this project does not instantiate - see reachability below.

  • @opentelemetry/* bumped past the releases carrying the vulnerable protobufjs / @grpc/grpc-js ranges, and @modelcontextprotocol/sdk bumped past the one carrying vulnerable ajvfast-uri.
  • Narrow pnpm.overrides for ws and undici - pinned by discord.js / @discordjs/ws, and the only advisories that were on a default live code path. protobufjs was deliberately not blanket-overridden: forcing a major across the @grpc/grpc-js range is a wire-format risk for no benefit, and it sits behind OTEL_ENABLED regardless.
  • Three OpenTelemetry packages that mcp-core never imports were dropped outright, and two more moved to devDependencies - the smallest production tree is the cheapest thing to audit.
  • astro, @astrojs/starlight and sharp moved from dependencies to devDependencies in the site workspace. The docs site is private: true and is never published; its build tooling does not belong in anyone’s production tree.
Terminal window
pnpm audit # 17 advisories
SeverityCountPackages
critical2vitest
high5astro, brace-expansion, sharp
moderate6@hono/node-server, astro, turbo
low4astro, esbuild, turbo

Every entry except @hono/node-server is build- and test-time only. vitest, esbuild, turbo, astro, sharp and brace-expansion are absent from both published tarballs. They are real advisories for a contributor running this repo; they are not supply-chain exposure for anyone installing @discord-mcp/cli.

CI gates on --prod for exactly that reason, and now runs weekly on a schedule rather than only on push - the absence of that schedule is why three months of drift went unnoticed.

pnpm audit walks the dependency graph. It cannot tell that the vulnerable code is never loaded by what discord-mcp actually ships.

Not reachable - the SDK’s HTTP transport, which this project does not ship

Section titled “Not reachable - the SDK’s HTTP transport, which this project does not ship”

discord-mcp is stdio-only at v1.0.0 (see v1.0.0 readiness). @modelcontextprotocol/sdk bundles a Streamable-HTTP server transport whose dependency subtree is installed but never imported by startStdio. The one remaining production advisory lives entirely inside it.

Shipping an HTTP transport in a v1.x minor makes that subtree live. When that happens this analysis must be redone before the release, not after.

Not reachable by default - the OpenTelemetry export path

Section titled “Not reachable by default - the OpenTelemetry export path”

OTEL_ENABLED defaults to false, and with it off mcp-server skips SDK boot entirely, so the gRPC/protobuf exporter stack is never imported. Operators who turn telemetry on should treat advisories in that subtree as live and pin accordingly.

Reachable - and therefore fixed rather than explained away

Section titled “Reachable - and therefore fixed rather than explained away”

undici is the HTTP client behind every Discord REST call and ws is the WebSocket layer behind the optional Gateway. Both sit on a default or near-default path, so both were overridden to patched ranges rather than rationalised. Re-check both on every audit: a future advisory on either lands squarely on live code.

BucketLive in a default stdio deployment?
SDK HTTP-transport subtree (1 moderate)No - HTTP transport not shipped
OTLP exporter subtreeNo - OTEL_ENABLED=false by default
Build and test tooling (16 advisories)No - absent from both tarballs

0 critical and 0 high in the production tree. 0 advisories with a demonstrated exploit path from Discord content, agent input, or operator config in the default stdio configuration.

PriorityFindingStatus
P0-None
P1-None
P2@hono/node-server path traversal via the SDKBlocking for any future HTTP transport; inert today. Bump the SDK when a release ships @hono/node-server >= 2.0.5.
P2Build-tooling advisories (vitest, astro, turbo, sharp)Not shipped. Bump on the normal dependency cadence; dependabot now watches the workflow actions and can be extended to npm.
Terminal window
pnpm install --frozen-lockfile
pnpm audit --audit-level=high --prod # the CI gate - exit 0
pnpm audit # full tree, including dev
pnpm why @hono/node-server # confirm the SDK HTTP-transport path

Two adjacent supply-chain guards run in the same CI job:

Terminal window
pnpm exec publint --strict packages/mcp-core
pnpm exec publint --strict packages/mcp-server
node .github/scripts/assert-no-workspace-protocol.mjs

The last one guards a different failure class entirely: pnpm rewrites the workspace: protocol on pack, npm does not, and a published manifest containing "@discord-mcp/core": "workspace:*" fails every consumer install and cannot be repaired without a deprecate-and-republish.