Post

CVE-2026-49284: ExpectedIssuer and InResponseTo binding bypass in SimpleSAMLphp

CVE-2026-49284: ExpectedIssuer and InResponseTo binding bypass in SimpleSAMLphp

I reported a SAML SP state-binding issue in SimpleSAMLphp that was published as CVE-2026-49284 / GHSA-q8r6-xj3f-wrrm.

The issue affected SP-initiated login flows in multi-IdP deployments. If SimpleSAMLphp created state for one expected IdP, but later received a valid response from a different trusted IdP, the ACS path logged a warning and continued processing instead of rejecting the response.

That issuer mismatch became security-relevant when combined with an unsigned response-level InResponseTo and a signed assertion that did not carry its own SubjectConfirmationData/InResponseTo.

Advisory

  • CVE: CVE-2026-49284
  • GitHub Advisory: GHSA-q8r6-xj3f-wrrm
  • Package: simplesamlphp
  • Affected version listed in advisory: 2.5.0
  • Patched versions listed in advisory: none
  • Severity: High 7.1/10
  • CVSS: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:H/A:N
  • CWE: CWE-345: Insufficient Verification of Data Authenticity

Root Cause

In an SP-initiated SAML login, the SP chooses an IdP and sends an AuthnRequest. SimpleSAMLphp stored that selected IdP in state as ExpectedIssuer.

The expected security property is straightforward:

If the SP created login state for IdP A, then a response from IdP B should not satisfy that state.

The vulnerable behavior broke that property. When the ACS received a response from an issuer different from ExpectedIssuer, the code logged a warning and continued into response processing.

The second part of the issue was request correlation:

  • the outer Response/@InResponseTo can point to the SP state;
  • the signed assertion may omit SubjectConfirmationData/@InResponseTo;
  • the code accepted the response as long as it did not see conflicting values.

That meant an unsigned response-level InResponseTo could bind the message to SP-initiated state, while the signed assertion itself did not cryptographically carry the same request binding.

Attack Shape

The practical scenario is a multi-IdP SP deployment where IdPs are not interchangeable security principals.

Example:

  1. The SP starts a login flow for IdP A.
  2. The saved state records ExpectedIssuer = IdP A.
  3. The attacker obtains a valid signed assertion from IdP B.
  4. The outer SAML Response contains InResponseTo for the SP state created for IdP A.
  5. The signed assertion does not include SubjectConfirmationData/InResponseTo.
  6. The ACS accepts the assertion from IdP B while completing state created for IdP A.

This is not signature forgery. IdP B’s assertion can be validly signed as IdP B. The bug is that the SP used unsigned response-level request correlation to satisfy state that was intentionally created for a different IdP.

Impact

The impact depends heavily on the deployment.

The issue matters most when:

  • the SP trusts multiple IdPs;
  • those IdPs represent different tenants, assurance levels, or attribute namespaces;
  • the application gives security meaning to the selected or expected IdP;
  • identifiers or attributes from different IdPs can collide or be interpreted globally;
  • enable_unsolicited is used as part of the deployment’s defense against IdP-initiated login.

In those deployments, a lower-trust IdP can satisfy SP state created for a different expected IdP. That can bypass IdP selection, tenant routing, or assurance-level assumptions.

Validation Matrix

During triage, I used a small matrix to separate the current behavior from the intended behavior.

The vulnerable behavior accepted these cases:

1
2
3
4
5
solicited_outer_only          ACCEPT
solicited_both_match          ACCEPT
solicited_both_mismatch       REJECT
unsolicited_no_inresponseto   ACCEPT
unsolicited_scd_only          ACCEPT

The important rows were:

  • solicited_outer_only: Response/InResponseTo is present, but signed SubjectConfirmationData/InResponseTo is missing.
  • unsolicited_scd_only: response-level InResponseTo is absent, but assertion-level SubjectConfirmationData/InResponseTo is present.

The intended fix direction was:

  • reject ExpectedIssuer mismatches in SP-initiated flows;
  • for solicited responses, require both Response/InResponseTo and SubjectConfirmationData/InResponseTo to be present and to match the AuthnRequest ID;
  • for unsolicited responses, reject if either InResponseTo value is present.

Why This Was Subtle

The vulnerable flow was not a single missing if around a signature check.

It combined:

  • state created for one selected IdP;
  • response processing for a different trusted IdP;
  • acceptance of assertion-only signatures;
  • request correlation based on unsigned response-level data;
  • missing rejection when assertion-level SubjectConfirmationData/InResponseTo was absent.

Each piece can appear compatible with existing SAML deployments in isolation. The security issue appears when the SP treats those pieces together as enough to complete an SP-initiated flow for a specific expected IdP.

References

This post is licensed under CC BY 4.0 by the author.