HIGH auth bypassaspnetsaml

Auth Bypass in Aspnet with Saml

Auth Bypass in Aspnet with Saml — how this specific combination creates or exposes the vulnerability

ASP.NET applications that rely on SAML for authentication can be exposed to an Auth Bypass when SAML assertions are not rigorously validated before establishing local authentication state. A common pattern is to create a claims identity and sign in the user after a single SAML response, without re-checking anti-forgery tokens, session binding, or proper issuer/audience verification. This mismatch between the SAML security context and the ASP.NET authentication pipeline can allow an attacker to reuse or manipulate assertions across sessions or applications.

One realistic attack chain involves an identity provider (IdP) issuing a SAML response with an audience that is broader than expected. If the relying party service does not validate the AudienceRestriction condition strictly, an attacker can present the same assertion to a different service endpoint within the same ASP.NET application. Because the application may only check NameID for sign-in and does not correlate the SAML SubjectConfirmation with the current session, the attacker can effectively authenticate as another user without credentials. This aligns with BOLA/IDOR patterns where identifier-based access control is missing or incorrectly enforced after SAML login.

Insecure token handling can further amplify the risk. For example, if the application caches the SAML response or the NameID in insecure server-side or client-side state and uses it for later authorization decisions, tampering becomes easier. An attacker who can inject or predict a NameID might escalate privileges by leveraging horizontal escalation techniques across tenants or roles. Because the ASP.NET pipeline treats the SAML-derived identity as trusted post-login, there is no additional step to re-validate authorization scopes per request, which can lead to Property Authorization failures that expose sensitive endpoints.

Another vector arises from missing or misconfigured Single Logout (SLO). If the application does not properly invalidate local authentication tickets when a SAML logout notification is received, a signed-in session may persist after the IdP considers it terminated. An attacker who gains access to a browser session can reuse local cookies and maintain access even after the SAML session on the IdP has ended. This session persistence issue compounds risks when combined with weak transport protections or when assertions are logged in plaintext.

To detect these issues, scanning with middleware that parses SAML responses and checks issuer, audience, conditions, and SubjectConfirmation is essential. Tools that understand the ASP.NET authentication pipeline and SAML profiles can correlate runtime behavior with metadata from the SecurityTokenDescriptor and the SAML protocol bindings. The goal is to ensure that every SAML-based login results in a tightly bound, short-lived local identity with proper checks on each request, rather than trusting the initial assertion indefinitely.

Saml-Specific Remediation in Aspnet — concrete code fixes

Remediation centers on strict validation of SAML responses and tight coupling between the SAML security context and ASP.NET authorization checks. Always validate the issuer, audience, and conditions (NotBefore/NotOnOrAfter), and bind the SubjectConfirmation to the current session. Do not rely solely on the NameID for access control; re-authorize sensitive actions using local policy checks.

Below is a concrete example of configuring SAML2 authentication in ASP.NET Core with strict audience and issuer validation. This example uses the Sustainsys.Saml2 library and shows how to enforce constraints that mitigate common bypass vectors.

// Program.cs or Startup.cs
using Sustainsys.Saml2;
using Sustainsys.Saml2.AspNetCore2;
using Sustainsys.Saml2.Configuration;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddAuthentication()
    .AddSaml2(options =>
    {
        options.SPOptions.EntityId = new EntityId("https://your-app.example.com/saml");
        options.IdentityProviders.Add(new IdentityProvider(
            new EntityId("https://idp.example.com/saml/metadata"),
            options.SPOptions)
        {
            MetadataLocation = "https://idp.example.com/saml/metadata",
            // Require signed assertions and responses
            WantAssertionsSigned = true,
            WantAuthnRequestsSigned = false
        });

        // Enforce strict session binding
        options.SPOptions.ServiceCertificates.Add(new X509Certificate2("path/to/cert.pfx", "cert-password"));

        // Limit allowed audiences and issuers
        options.WantSamlResponseSigned = true;
        options.WantAssertionSigned = true;
        options.RequireAuthenticationRequestSigned = false;

        // Custom validation hook to enforce additional constraints
        options.SPOptions.IdentityProviders["https://idp.example.com/saml/metadata"].MetadataChanged += (s, e) =>
        {
            // Ensure conditions are enforced
            var idp = (IdentityProvider)s;
            idp.SigningKeys.AddConfiguredKey(new X509Certificate2("idp-signing.cer"));
        };
    });

app.UseAuthentication();
app.UseAuthorization();

In the above, WantAssertionsSigned and WantSamlResponseSigned ensure cryptographic integrity. The SPOptions settings enforce that the audience matches the service provider entity ID and that the issuer matches the known IdP. To bind the assertion to the session, include a SubjectConfirmation with Bearer subject confirmation and validate the InResponseTo field against the AuthNRequest ID. The following snippet shows a minimal SAML response example that includes the necessary elements for a secure exchange:

<?xml version="1.0" encoding="UTF-8"?>
<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
                 xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
                 ID="_123456"
                 Version="2.0"
                 IssueInstant="2024-01-01T12:00:00Z"
                 Destination="https://your-app.example.com/saml/acs"
                 InResponseTo="req_abc"
                 Consent="urn:oasis:names:tc:SAML:2.0:consent:unspecified">
  <saml:Issuer>https://idp.example.com/saml/metadata</saml:Issuer>
  <samlp:Status>
    <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
  </samlp:Status>
  <saml:Assertion ID="assertion_1"
                  Version="2.0"
                  IssueInstant="2024-01-01T12:00:00Z"
                  Issuer="https://idp.example.com/saml/metadata"
                  Destination="https://your-app.example.com/saml/acs">
    <saml:Subject>
      <saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"
                   NameQualifier="https://idp.example.com/saml/metadata"
                   SPNameQualifier="https://your-app.example.com/saml"
                   >[email protected]</saml:NameID>
      <saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
        <saml:SubjectConfirmationData<ResponseLocator>
          InResponseTo="req_abc"
          Recipient="https://your-app.example.com/saml/acs"
          NotOnOrAfter="2024-01-01T12:05:00Z"/>
      </saml:SubjectConfirmation>
    </saml:Subject>
    <saml:Conditions NotBefore="2024-01-01T11:55:00Z"
                      NotOnOrAfter="2024-01-01T12:05:00Z">
      <saml:AudienceRestriction>
        <saml:Audience>https://your-app.example.com/saml</saml:Audience>
      </saml:AudienceRestriction>
    </saml:Conditions>
    <saml:AttributeStatement>
      <saml:Attribute Name="roles" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri">
        <saml:AttributeValue>user</saml:AttributeValue>
      </saml:Attribute>
    </saml:AttributeStatement>
  </saml:Assertion>
</samlp:Response>

On the ASP.NET side, after a successful SAML sign-in, create a local claims identity that is bound to the SAML session and includes only the minimal required claims. Re-validate roles and permissions on each request using policies, rather than trusting the SAML-derived identity for fine-grained authorization. This approach reduces the impact of a compromised assertion and aligns with defense-in-depth principles for Auth Bypass scenarios.

Related CWEs: authentication

CWE IDNameSeverity
CWE-287Improper Authentication CRITICAL
CWE-306Missing Authentication for Critical Function CRITICAL
CWE-307Brute Force HIGH
CWE-308Single-Factor Authentication MEDIUM
CWE-309Use of Password System for Primary Authentication MEDIUM
CWE-347Improper Verification of Cryptographic Signature HIGH
CWE-384Session Fixation HIGH
CWE-521Weak Password Requirements MEDIUM
CWE-613Insufficient Session Expiration MEDIUM
CWE-640Weak Password Recovery HIGH

Frequently Asked Questions

How does middleBrick detect Auth Bypass risks related to SAML in ASP.NET?
middleBrick scans the unauthenticated attack surface and, when an OpenAPI/Swagger spec is available, correlates SAML-related endpoints and metadata with runtime behavior. It checks for missing issuer/audience validation, weak SubjectConfirmation usage, and session-binding gaps, then reports findings with remediation guidance.
Can the free plan be used to assess SAML-based login flows in ASP.NET applications?
Yes, the Free plan ($0) allows 3 scans per month, which is sufficient to run black-box scans against SAML endpoints in ASP.NET applications and receive prioritized findings and remediation guidance.