The TypeScript 2.2.0 remediation addressed gaps where credential schemas inadvertently removed the issuer field during routine object processing. This critical discovery in early 2026 highlighted a systemic weakness in how the Model Context Protocol (MCP) handled authentication across distributed environments. The vulnerabilities, identified as CVE-2026-115563 and CVE-2026-104850, presented a significant risk to the integrity of automated agentic systems by allowing unauthorized access to sensitive authentication material. Both security flaws received a CVSS v3.1 score of 7.5, classifying them as High severity threats that required immediate attention from the developer community. The issue was not merely a coding error but a fundamental breakdown in the trust boundary between the client and the remote servers it connects to. Because MCP is designed to facilitate seamless interaction between AI models and various data sources, the security of these connections is paramount to preventing large-scale credential harvesting. The subsequent patches released for both the Python and TypeScript SDKs represent a major step forward in hardening the protocol against sophisticated redirection attacks that could compromise entire enterprise ecosystems.
1. The Mechanics: Understanding the Broken Trust Boundary
The core of the vulnerability lies in a broken security assumption regarding how an MCP server influences the choice of an authorization server. In the affected versions of the SDKs, a remote server could effectively dictate which endpoint should receive the client’s credentials during the OAuth discovery process. This logic allowed a malicious or compromised MCP server to advertise an attacker-controlled endpoint as a legitimate authorization server. When the client attempted to perform routine authentication tasks, it would inadvertently transmit sensitive data—including OAuth client secrets, refresh tokens, and authorization codes—to the malicious destination. This failure to enforce a strict separation between the resource server and the authority that issues credentials created a path for silent data exfiltration. The vulnerability demonstrated that a client possessing credentials for a legitimate issuer could be tricked into presenting those same secrets to an untrusted entity simply because the remote MCP server claimed the untrusted entity was the correct destination for the session.
Under the framework of RFC 9728, an OAuth protected resource is permitted to publish metadata that identifies its associated authorization servers. In a standard, secure implementation, the client uses this metadata to discover where it should authenticate. However, the protocol does not inherently grant a resource server the authority to take ownership of credentials issued by a different, unrelated authorization server. The vulnerability in the MCP SDKs occurred because this distinction was not programmatically enforced. A malicious actor could set up a deceptive MCP server that returned a crafted metadata document pointing to a rogue token endpoint. Because the SDK did not verify whether the existing credentials in its possession were actually valid for that newly discovered endpoint, it would proceed with the request as if the relationship were legitimate. This created a scenario where authentication materials were disclosed before any downstream security controls, such as token binding or rotation, could intervene to protect the user or the application.
The impact of this credential isolation failure was particularly acute for unattended authentication flows, such as those using client credentials or long-lived refresh tokens. Unlike interactive sign-in processes where a human user might notice a suspicious URL or a redirection to an unfamiliar domain, unattended flows happen in the background without manual oversight. In these cases, the SDK might attempt to refresh an expired access token by sending the stored refresh token to the endpoint provided by the malicious MCP server. Depending on the specific configuration of the OAuth provider, the exposed material could include not only the tokens themselves but also PKCE verifiers and signed client assertions. Once an attacker obtains these materials, they may be able to masquerade as the legitimate client against the original authorization server. This underscores the necessity of the fix, which ensures that the destination for a credential-bearing request is always validated against the identity of the issuer that originally provided those credentials.
2. Python Remediation: Establishing Identity through Validation
The remediation for the Python SDK, specifically in versions 1.30.0 and 2.2.0, focused on establishing a definitive identity for the authorization server before any sensitive data is transmitted. The first step in this process is for the client to anticipate the correct issuer. This is achieved by deriving an expected issuer identifier from the protected resource metadata or the resource server’s origin. By defining what the issuer should be before the discovery process concludes, the SDK creates a baseline against which all subsequent server claims can be measured. This proactive approach prevents the client from blindly following a redirection path provided by an untrusted remote server. If the MCP server attempts to advertise an authorization server that does not align with this anticipated identity, the client can detect the discrepancy early in the lifecycle of the connection and terminate the process before credentials are ever put at risk.
Once the expected issuer is identified, the patched Python SDK employs a rigorous validation function to confirm the authenticity of the metadata it receives. The system now uses the validate_metadata_issuer() utility to compare the issuer field within the discovered authorization server metadata against the expected value. This check is crucial because it addresses a legacy discovery fallback path where a client might retrieve metadata from an MCP server’s origin. Without this validation, a malicious document could claim one entity as the issuer while providing token endpoints controlled by another. By enforcing a strict match between the claimed issuer and the discovery URL, the Python implementation adheres to the security requirements of RFC 8414. Any mismatch now triggers an OAuthFlowError, ensuring that the client does not inadvertently engage with a rogue endpoint that is attempting to masquerade as a trusted authorization authority.
In addition to metadata validation, the Python fix ensures that existing client registrations and tokens are strictly bound to their respective issuers. Before the SDK reuses any stored credentials for a new authorization flow, it verifies that the credentials actually belong to the current expected issuer. If the system detects that a registration is bound to a different authorization server, it can safely discard the old state and initiate a new registration or authorization process as required. This prevents the “credential reuse” scenario that was at the heart of the original vulnerability. Furthermore, the fix standardizes this behavior across all discovery paths, including the 403 insufficient_scope “step-up” flows that were previously inconsistent in their application of security checks. By closing these gaps, the Python SDK ensures that every path leading to a credential-bearing request is subject to the same high standards of identity verification and issuer binding.
3. TypeScript Fixes: Preserving Credential Integrity and Binding
The TypeScript SDK remediation, released in @modelcontextprotocol/sdk 1.31.0 and @modelcontextprotocol/client 2.2.0, introduced a robust mechanism for tagging and managing credentials based on their origin. In previous versions, stored tokens and client information often lacked a reliable connection to the servers that issued them, making them vulnerable to redirection. The update addresses this by ensuring that every saved token and registration record now includes a specific issuer property. This property acts as a permanent tag that identifies the exact authorization server associated with the credential. By maintaining this identity at the data layer, the SDK can perform real-time checks to ensure that a secret is never presented to the wrong endpoint. This change effectively turns a generic token into an issuer-bound asset, significantly reducing the surface area for redirection attacks in complex AI integration environments.
A critical component of the TypeScript fix is the introduction of a specialized function designed to remove mismatched credentials from the active session. The discardIfIssuerMismatch() utility operates by comparing the issuer tag on a stored credential with the authorization server currently selected during the MCP discovery process. If a mismatch is found—such as when a malicious MCP server tries to claim a refresh token issued by a trusted provider—the SDK automatically discards the stored secret. This automated defensive action ensures that the client remains secure even if the remote server is compromised. In the context of 2.x releases, this logic is further bolstered by the AuthorizationServerMismatchError, which provides a clear and actionable signal when a security boundary is breached. These combined measures create a defensive shield that prevents the reuse of sensitive materials across different trust domains.
Beyond the immediate validation of tokens, the TypeScript update resolves a subtle but dangerous issue related to how data is processed through schemas and serialization layers. Prior to the 2.2.0 release, certain routine object processing tasks would inadvertently strip the issuer field from credential records, essentially “cleaning” the data of its security-relevant identity. This meant that even if a developer implemented storage correctly, the issuer binding could be lost before the data reached the authentication logic. The remediation ensures that the issuer property is preserved throughout the entire lifecycle of the credential object, from initial storage to final transmission. This fix is particularly important for developers using custom providers or complex data pipelines, as it guarantees that the necessary identity information remains intact and available for validation at every step of the token acquisition process.
4. Implementation Requirements: Why Upgrading Is Only the First Step
It is a common misconception in software security that updating a library is always sufficient to resolve a vulnerability. In the case of the MCP SDK fixes, simply moving to the latest version does not automatically secure an application against every possible exploit path. Because the SDK cannot always infer the correct authorization server for pre-provisioned credentials, developers must manually specify the issuer in their code. In the Python implementation, this involves using the issuer argument when configuring a ClientCredentialsOAuthProvider or a PrivateKeyJWTOAuthProvider. By explicitly naming the authorization server, the developer provides the SDK with the ground truth it needs to perform validation. Without this manual configuration, the provider might still be susceptible to following whichever server the remote MCP endpoint advertises, as the issuer argument remains optional for the sake of backward compatibility.
The TypeScript SDK requires a similar proactive configuration through the expectedIssuer parameter. When defining an OAuth provider, such as the ClientCredentialsProvider, engineering teams must ensure that the expected issuer is clearly defined in the provider parameters. This is essential for protecting credentials like client secrets and signed assertions that are used in non-interactive flows. If the expectedIssuer is omitted, the SDK lacks the reference point required to trigger the discardIfIssuerMismatch() logic, potentially leaving the application in a vulnerable state despite having the latest patches installed. This requirement emphasizes the shift toward a “zero-trust” model for remote integrations, where the client assumes no inherent relationship between the resource server and the authorization authority unless specifically instructed by the application developer.
Another critical step for developers involves the comprehensive cleanup of legacy credential storage. Records created before the security updates were applied do not contain the necessary issuer tags, making them “unstamped” and potentially dangerous. The SDKs have compatibility behaviors that might allow these old credentials to be associated with the very first authorization server they contact after the upgrade. If that first server is malicious, the application will effectively bind its legitimate secrets to an attacker’s domain. To mitigate this risk, developers are strongly advised to clear their existing token databases or manually update their records to include the correct issuer property. This migration process is a vital part of the remediation cycle, as it ensures that the security properties of the patched SDK are applied consistently to all historical data.
5. Risk Mitigation: Rotating Secrets and Verifying Custom Logic
When a security vulnerability involves the potential disclosure of authentication materials, the standard response must include a thorough rotation of all secrets. If an MCP client interacted with an untrusted or unverified remote server prior to the implementation of these patches, there is a realistic possibility that its refresh tokens and client secrets were exfiltrated. Merely patching the software does not invalidate any credentials that are already in the hands of an attacker. Therefore, engineering teams should proactively rotate client secrets and revoke all active refresh tokens associated with the affected applications. This action resets the security state of the environment and ensures that even if past sessions were compromised, the stolen materials can no longer be used to gain unauthorized access to the legitimate authorization server.
Auditing custom storage logic is another essential task for maintaining the security of the MCP integration. Many developers implement their own versions of saveTokens() or saveClientInformation() to integrate with specific database technologies or enterprise secret managers. It is imperative to verify that these custom implementations have been updated to handle and preserve the new issuer property. If a custom storage callback inadvertently strips the issuer field when saving a token, the security checks in the patched SDK will fail to find the necessary identity tag during the next session, effectively bypassing the protection. Developers should review their serialization and deserialization code to ensure that the issuer-binding data is treated as a first-class citizen alongside the tokens themselves, maintaining the integrity of the credential lifecycle.
In the Python ecosystem, developers must also be aware of how DeprecationWarning messages are handled. The patched Python SDK issues a warning when an issuer is omitted from a provider configuration, but because Python often hides these warnings by default in production environments, the signal may be missed. This can lead to a situation where a security-sensitive omission persists for a long period without the knowledge of the operations team. To prevent this, teams should configure their logging or CI/CD pipelines to treat these specific warnings as errors during the testing phase. By forcing the explicit definition of the issuer, organizations can ensure that they are utilizing the full protective capabilities of the 1.30.0 and 2.2.0 releases, rather than relying on default behaviors that may favor compatibility over maximum security.
6. The Final Audit: Ensuring Comprehensive Security Coverage
The process of securing an MCP-based application concludes with a comprehensive audit of the entire deployment environment. Engineering teams should start by verifying the exact versions of the SDKs present in their lockfiles and deployed artifacts. It is not enough to check the package.json or requirements.txt files, as transitive dependencies or cached versions can sometimes lead to the use of vulnerable code. For Python, the versions must be mcp 1.30.0, 2.2.0, or later. For TypeScript, the targets are @modelcontextprotocol/sdk 1.31.0 and @modelcontextprotocol/client 2.2.0. This mechanical verification ensures that the foundational security logic is in place before the team begins looking at higher-level application configurations and custom code paths.
A secondary focus of the audit involves identifying any intentional or unintentional security opt-outs. For example, the TypeScript SDK provides a configuration option called skipIssuerMetadataValidation, which, if set to true, disables the very checks designed to prevent redirection attacks. While there may be legitimate edge cases for this setting in highly controlled testing environments, it should never be active in a production system that connects to external or third-party MCP servers. Similarly, the audit should review application logs to identify any past connections to suspicious or unverified remote endpoints. If logs show that a client was redirected to an unexpected authorization server before the patches were applied, that information can be used to prioritize the revocation of specific credentials and the investigation of potential unauthorized activity.
The vulnerabilities identified in early 2026 served as a powerful reminder that as the infrastructure for AI agents becomes more complex, the security of basic authentication protocols becomes even more critical. The transition toward issuer-bound credentials represents a maturing of the Model Context Protocol, moving it closer to the security standards expected of enterprise-grade integration frameworks. By following the detailed remediation steps and maintaining a rigorous audit process, developers protected their systems from sophisticated credential theft. This proactive stance on security was essential for fostering trust in automated systems, ensuring that the benefits of remote model integration were not overshadowed by the risks of systemic data exposure. The lessons learned from these fixes shaped the development of secure agentic architectures throughout the remainder of the year.
