This release includes 4 security fixes for security teams reviewing exposed deployments.
Published 2mo
MCP Developer Tools
✓ No known CVEs patched
This release patches 4 known CVEs
Topics
mcp
mcp-client
mcp-sdk
mcp-server
mcp-servers
rust
Affected surfaces
auth
deps
Summary
AI summarySSRF 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 discovery —
JwtValidator::discover_jwks_uriandJwksCache::get_client_for_issuernow accept an optionalSsrfValidatorthat validates URLs before any network I/O. Previously,reqwest::get()was called directly on user-controlled issuer claims, allowing SSRF against internal services. New constructorsJwtValidator::new_with_ssrf()andJwksClient::with_ssrf_validator()enable SSRF-protected operation. Thessrfmodule is now unconditionally available (was previously gated behindmcp-ssrffeature). - JWT audience field RFC 7519 compliance —
StandardClaims.audchanged fromOption<String>toOption<Vec<String>>usingserde_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 limit —
JwksClient::fetch_and_cachenow enforces a 64KB response body limit before JSON parsing, preventing memory exhaustion from malicious JWKS endpoints. - DPoP server nonce implementation —
generate_proof_with_paramsnow embeds server-provided nonces as the"nonce"claim in DPoP proofs per RFC 9449 §8. Previously, the nonce parameter was silently discarded. - PKCE
plainmethod removed in WASM —verify_pkcein 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::ConstantTimeEqto 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) toRateLimitConfigwith automatic eviction of expired entries when capacity is reached, preventing OOM under IP spoofing attacks. lz4_flexupgraded to 0.11.6 — Fixes RUSTSEC-2026-0041 (HIGH 8.2): information leak from uninitialized memory during decompression of invalid data.quinn-protoupgraded to 0.11.14 — Fixes RUSTSEC-2026-0037 (HIGH 8.7): denial of service in Quinn endpoints via malformed QUIC packets.lrureplaced withmoka— Resolves RUSTSEC-2026-0002 (unsoundIterMut). OAuth2 token cache now usesmoka::future::Cache(thread-safe, lock-free, with TTL support).
Fixed
no_stdcompliance inturbomcp-types— Added#![cfg_attr(not(feature = "std"), no_std)]and cfg-conditionalHashMap/BTreeMapimports incontent.rs,results.rs,protocol.rs. Changedstd::fmttocore::fmtintraits.rsandprotocol.rs. Layer 1 crates now correctly supportno_std + alloc.biasedadded to shutdown-criticalselect!blocks —tokio::select!in the line transport main loop and client message dispatcher now usesbiased;to ensure shutdown signals are always checked first.- Production
unwrap()removed from HTTP transport —HeaderValue::from_str().unwrap()on session IDs replaced with graceful fallback. - Mutex poisoning risk eliminated —
std::sync::Mutexin channel transport replaced withparking_lot::Mutex(never poisons). - Unnecessary allocation in router —
request.params.clone().unwrap_or_default()replaced with borrow pattern in the initialize handler. - Dead code cleanup — Removed unused
detect_server_initiated_typefunction. Changed unusedSessionManagermethods topub(crate). - Workspace dependency consistency —
turbomcp-grpcnow uses{ workspace = true }for internal deps instead of inline path specifications. - License compliance — Added
OpenSSLandZlibtodeny.tomlallowlist. Added advisory ignores for compile-time-only crates (paste,proc-macro-error).
Changed
- Fraudulent security tests replaced — Three tests in
security_attack_scenarios.rsthat asserted on test data (not SDK behavior) were rewritten with meaningful assertions against actual crate behavior. - Vacuous tests fixed —
test_dispatcher_smoke(zero assertions) replaced withtest_bidirectional_types_compilewith 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
Related context
Beta — feedback welcome: [email protected]