Skip to content

v0.3.0

Choose a tag to compare

@ni-c ni-c released this 13 Aug 18:49
· 40 commits to main since this release
v0.3.0
ed017f2

Security-hardening release. Every change comes from an internal security audit of the hub; the full deployment guidance now lives in SECURITY.md.

Security

  • Resource-bound tokens (RFC 8707): a client that sends a resource indicator receives an access token bound to /hub or one /<name>/mcp — usable nowhere else on the hub. The login/consent pages display the requested resource, and the code/refresh exchanges verify it. Set RESOURCE_BOUND_TOKENS=true to make the indicator mandatory for every new token (recommended; legacy global tokens then stop working and clients re-authorize once).
  • Access tokens now expire after 15 minutes (down from 24 hours); refresh tokens keep rotating with family-reuse detection.
  • Offline revocation: mcp-hub-admin clients list|revoke (run against the mounted /data while the hub is stopped) removes a client's approval and refresh tokens and immediately rejects its outstanding access tokens via a revokedBefore marker.
  • Stricter JWT verification: the EdDSA algorithm is pinned and issuer, audience, subject and client_id are validated explicitly.
  • Request limits: cheap per-IP rate limits guard /register, /authorize, /token, /login and /consent before any body parsing; authenticated MCP traffic passes a per-client gate (MCP_REQUESTS_PER_MINUTE, default 120, and MCP_MAX_CONCURRENT_REQUESTS, default 4); the MCP JSON body limit drops to 1 MB (MCP_BODY_LIMIT) and is parsed only after bearer auth; the Node server gets header/request timeouts (HTTP_HEADERS_TIMEOUT_MS, HTTP_REQUEST_TIMEOUT_MS).
  • Browser hardening on the interactive auth pages: CSP with frame-ancestors 'none' and form-action 'self', X-Frame-Options: DENY, nosniff, Referrer-Policy: no-referrer; x-powered-by removed.

Supply chain

  • Base images, the uv helper and every GitHub Action are pinned to digests/commit SHAs; npm installs run with --ignore-scripts.
  • CI gates publishing behind CodeQL, a Trivy scan of both platform images (HIGH/CRITICAL, zero findings) and npm audit; published images ship an SBOM and mode=max provenance. Dependabot watches npm, Docker and Actions weekly.
  • The runtime image replaces the base image's bundled npm 10 with npm 12 and patches its two remaining vendored CVEs (brace-expansion, ip-address) in place.
  • The compose example now runs with a read-only root filesystem, explicit tmpfs mounts and all capabilities dropped.

Breaking / behavioral changes

  • /health (per-server status) now requires a bearer token. The new unauthenticated /livez answers liveness only; the image HEALTHCHECK uses it, and external monitoring should too. livez joins the reserved server names.
  • Access tokens last 15 minutes — clients must use the refresh flow (Claude Web and Claude Code do).
  • Enabling RESOURCE_BOUND_TOKENS=true invalidates previously issued global access/refresh tokens; each client re-authorizes once.
  • curl was removed from the image and tini is now PID 1.
  • Install stdio server binaries at exact, reviewed versions in a custom image instead of downloading them at runtime via npx -y/uvx — required with the read-only root filesystem and strongly recommended regardless (see SECURITY.md).