Skip to content

Epistates/TurboMCP

v3.0.6 Security

This release includes 4 security fixes for security teams reviewing exposed deployments.

Published 2mo MCP Developer Tools
✓ No known CVEs patched
Read the diff → Tool health → What is this tool? →
This release patches 4 known CVEs

Topics

mcp mcp-client mcp-sdk mcp-server mcp-servers rust

Affected surfaces

auth deps

Summary

AI summary

SSRF bypass in JWT OIDC discovery fixed, audience field deserialization compliance restored, multiple dependency upgrades addressing information leaks and DoS.

Full changelog

[3.0.6] - 2026-03-18

Security

  • SSRF bypass in JWT OIDC discoveryJwtValidator::discover_jwks_uri and JwksCache::get_client_for_issuer now accept an optional SsrfValidator that validates URLs before any network I/O. Previously, reqwest::get() was called directly on user-controlled issuer claims, allowing SSRF against internal services. New constructors JwtValidator::new_with_ssrf() and JwksClient::with_ssrf_validator() enable SSRF-protected operation. The ssrf module is now unconditionally available (was previously gated behind mcp-ssrf feature).
  • JWT audience field RFC 7519 complianceStandardClaims.aud changed from Option<String> to Option<Vec<String>> using serde_with::OneOrMany, correctly handling both "aud": "single" and "aud": ["one", "two"] formats per RFC 7519 §4.1.3. Previously, tokens from enterprise IdPs (Google, Azure AD, Okta) using the array format would fail deserialization.
  • JWKS response size limitJwksClient::fetch_and_cache now enforces a 64KB response body limit before JSON parsing, preventing memory exhaustion from malicious JWKS endpoints.
  • DPoP server nonce implementationgenerate_proof_with_params now embeds server-provided nonces as the "nonce" claim in DPoP proofs per RFC 9449 §8. Previously, the nonce parameter was silently discarded.
  • PKCE plain method removed in WASMverify_pkce in the WASM auth provider now rejects the "plain" method, enforcing "S256" per RFC 7636 §4.2.
  • Constant-time comparison hardened in WASM — Replaced hand-rolled branchless comparison with subtle::ConstantTimeEq to resist LLVM optimizer constant-time assumption violations.
  • Internal error leakage in JSON-RPC responses — Error handler now generates an opaque UUID error ID for clients and logs the full internal error server-side, preventing reconnaissance via error messages.
  • Unbounded rate limiter memory — Added max_tracked_ips (default: 100,000) to RateLimitConfig with automatic eviction of expired entries when capacity is reached, preventing OOM under IP spoofing attacks.
  • lz4_flex upgraded to 0.11.6 — Fixes RUSTSEC-2026-0041 (HIGH 8.2): information leak from uninitialized memory during decompression of invalid data.
  • quinn-proto upgraded to 0.11.14 — Fixes RUSTSEC-2026-0037 (HIGH 8.7): denial of service in Quinn endpoints via malformed QUIC packets.
  • lru replaced with moka — Resolves RUSTSEC-2026-0002 (unsound IterMut). OAuth2 token cache now uses moka::future::Cache (thread-safe, lock-free, with TTL support).

Fixed

  • no_std compliance in turbomcp-types — Added #![cfg_attr(not(feature = "std"), no_std)] and cfg-conditional HashMap/BTreeMap imports in content.rs, results.rs, protocol.rs. Changed std::fmt to core::fmt in traits.rs and protocol.rs. Layer 1 crates now correctly support no_std + alloc.
  • biased added to shutdown-critical select! blockstokio::select! in the line transport main loop and client message dispatcher now uses biased; to ensure shutdown signals are always checked first.
  • Production unwrap() removed from HTTP transportHeaderValue::from_str().unwrap() on session IDs replaced with graceful fallback.
  • Mutex poisoning risk eliminatedstd::sync::Mutex in channel transport replaced with parking_lot::Mutex (never poisons).
  • Unnecessary allocation in routerrequest.params.clone().unwrap_or_default() replaced with borrow pattern in the initialize handler.
  • Dead code cleanup — Removed unused detect_server_initiated_type function. Changed unused SessionManager methods to pub(crate).
  • Workspace dependency consistencyturbomcp-grpc now uses { workspace = true } for internal deps instead of inline path specifications.
  • License compliance — Added OpenSSL and Zlib to deny.toml allowlist. Added advisory ignores for compile-time-only crates (paste, proc-macro-error).

Changed

  • Fraudulent security tests replaced — Three tests in security_attack_scenarios.rs that asserted on test data (not SDK behavior) were rewritten with meaningful assertions against actual crate behavior.
  • Vacuous tests fixedtest_dispatcher_smoke (zero assertions) replaced with test_bidirectional_types_compile with real assertions. test_oauth2_expired_authorization (sleep with no assertion) marked #[ignore] with documented implementation path.
  • Trybuild test documentation — Disabled trybuild tests now have precise reason strings and documented TODO items for v3 compile-fail scenarios.

Full Changelog: https://github.com/Epistates/turbomcp/compare/v3.0.5...v3.0.6

Breaking Changes

  • PKCE `plain` method removed in WASM; `verify_pkce` now rejects it and enforces `S256` per RFC 7636 §4.2

Security Fixes

  • CVE/RUSTSEC-2026-0041 — upgraded `lz4_flex` to 0.11.6, fixing HIGH severity (8.2) information leak from uninitialized memory during invalid data decompression
  • CVE/RUSTSEC-2026-0037 — upgraded `quinn-proto` to 0.11.14, fixing HIGH severity (8.7) denial‑of‑service via malformed QUIC packets
  • RUSTSEC-2026-0002 — replaced unsound `lru` crate with sound `moka` for OAuth2 token cache
  • SSRF bypass in JWT OIDC discovery fixed by adding optional `SsrfValidator` to `JwtValidator::discover_jwks_uri` and `JwksCache::get_client_for_issuer`

Weekly OSS security release digest.

The CVE patches and breaking changes that affected production tools this week. One email, every Sunday.

No spam, unsubscribe anytime.

Share this release

Track Epistates/TurboMCP

Get notified when new releases ship.

Sign up free

About Epistates/TurboMCP

TurboMCP SDK: Enterprise MCP SDK in Rust

All releases →

Beta — feedback welcome: [email protected]