Back to advisories
CVE-2026-63672 GHSA-pr4x-6fj4-gm4h Medium CVSS 6.1

Unrestricted Identity Provider Selection in SAML Authentication

Unauthenticated users can control the Identity Provider (IdP) selection in SAML authentication due to insufficient validation. This advisory explains the issue in Saml.php, the proof of concept, potential impact, and recommended remediation.

Affected: egroupware < 26.7.20260702 Vendor: EGroupware Discovered: Reported: May 6, 2026 Patched: Jul 2, 2026 Reporter: Stefan Mitocaru
CVSS Vector: CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N

Details

EGroupware's SAML login handler passes the raw user-supplied idp request parameter directly to SimpleSAMLphp's requireAuth() after only checking that the value starts with https://. No validation is performed against a configured list of trusted Identity Provider entity IDs. An unauthenticated attacker can supply any HTTPS URL pointing to an IdP they control, redirecting the authentication flow to a malicious server.


Summary

Field Value
Advisory GHSA-pr4x-6fj4-gm4h
Severity Medium
CWE CWE-601 (URL Redirection to Untrusted Site)
Package egroupware (PHP)
Affected < 26.5.20260507
Vulnerability User-Controlled Identity Provider Selection
Impact Credential phishing, potential authentication bypass via forged SAML assertions

The login() function in api/src/Auth/Saml.php accepts an idp parameter from the HTTP request and forwards it to SimpleSAMLphp without verifying that it corresponds to a trusted, pre-configured Identity Provider. The only check applied is a regex that confirms the value begins with https://, which is trivially satisfied by any attacker-controlled HTTPS URL. This gives an unauthenticated attacker full control over which IdP processes the authentication request.


How it works

The vulnerable code is contained in the login() function of api/src/Auth/Saml.php:

// api/src/Auth/Saml.php
function login()
{
    // login (redirects to IdP)
    $as = new SimpleSAML\Auth\Simple(self::$auth_source);
    $as->requireAuth(preg_match('|^https://|', $_REQUEST['idp']) ?
        ['saml:idp' => $_REQUEST['idp']] : []);

The ternary expression evaluates whether $_REQUEST['idp'] starts with https://. If it does, the value is passed verbatim as the saml:idp option to requireAuth(), instructing SimpleSAMLphp to initiate authentication against that specific IdP. If it does not, an empty options array is passed and the default IdP is used.

The check provides no actual trust validation. It confirms only that the attacker typed https:// at the start of their URL. Any HTTPS endpoint, including one the attacker operates, satisfies the condition and will be used as the authentication target.


Root Cause

The application conflates URL format validation with trust validation. Checking that a string is a well-formed HTTPS URL says nothing about whether the endpoint it points to is a trusted party in the SAML federation. The correct control is an allowlist: the application should maintain a set of known, configured IdP entity IDs and reject any idp value that is not an exact match for one of them. The current implementation has no such list and performs no such check.


Prerequisites

  • No authentication is required. The vulnerability is reachable from the login page before any session exists.
  • The attacker needs a valid HTTPS endpoint they control that is capable of responding to SAML authentication requests.
  • A victim user must visit the crafted login URL, making this a user-interaction-required attack, typical of phishing scenarios.

Fix

Validate the idp parameter against a pre-configured allowlist of trusted IdP entity IDs before passing it to requireAuth(). The trusted list should be sourced from the application's SAML configuration, not derived from the request:

// Before (vulnerable): only format is checked, any HTTPS URL is accepted
$as->requireAuth(preg_match('|^https://|', $_REQUEST['idp']) ?
    ['saml:idp' => $_REQUEST['idp']] : []);

// After (safe): idp must exactly match a configured, trusted entity ID
$trusted_idps = self::get_trusted_idps(); // load from SAML config, not from request

$requested_idp = $_REQUEST['idp'] ?? '';

if (!in_array($requested_idp, $trusted_idps, true))
{
    // Log the attempt and fall back to the default IdP
    error_log('SAML: untrusted idp parameter rejected: ' . $requested_idp);
    $as->requireAuth([]);
}
else
{
    $as->requireAuth(['saml:idp' => $requested_idp]);
}

The allowlist must use strict comparison (true as the third argument to in_array) and must be loaded from a server-side configuration source that the user cannot influence.


Key Takeaways

  • Format validation is not trust validation. Confirming that a URL starts with https:// only verifies that TLS is in use on whatever server the attacker chose. It says nothing about whether that server is a trusted federation participant.
  • IdP selection must be server-side. Any application that supports multiple Identity Providers must maintain the list of permitted IdPs on the server and validate user input against it. The client must never be the authority on which IdP to use.
  • The attack surface is the login page itself. Because the vulnerable parameter is processed before authentication, no credentials or session are required to exploit this, making it trivially accessible to any internet-facing attacker.
  • SAML authentication bypass is a worst-case outcome. Depending on SimpleSAMLphp's metadata validation strictness, this vulnerability can escalate from phishing to full authentication bypass, granting the attacker arbitrary user impersonation including administrative access.

Proof of Concept

Proof of Concept Sanitized for safety
Note: This proof of concept is published for educational and defensive purposes after coordinated disclosure. Do not use it against systems you do not own or have explicit permission to test.

The attacker configures a SAML Identity Provider at a domain they control. This can be done with any SAML IdP software. The IdP is configured to capture incoming authentication requests and present a login form that mimics the legitimate EGroupware SSO page.

https://target.com/egroupware/login.php?idp=https://attacker.com/saml/idp

Because https://attacker.com/saml/idp starts with https://, the regex check passes and SimpleSAMLphp is instructed to authenticate against the attacker's IdP. Two outcomes are possible depending on the attacker's goals and the SimpleSAMLphp configuration:

  • Authentication bypass via forged assertion. If the target SimpleSAMLphp configuration does not strictly validate that the responding IdP is in its trusted metadata set, the attacker's IdP can issue a forged SAML assertion claiming the victim is any user, including an administrator:
<saml:Attribute Name="uid">
  <saml:AttributeValue>admin</saml:AttributeValue>
</saml:Attribute>
  • Credential phishing. The attacker's IdP presents a fake login form. The victim enters their credentials, which the attacker captures. The attacker can then optionally redirect the victim back to the real IdP to complete a transparent login, making the attack invisible.

Start securing your codebase today

Connect your repositories and let AI agents handle continuous scanning, research, and triage.

Have questions? Get in touch →