High severity8.6NVD Advisory· Published Mar 11, 2025· Updated Apr 15, 2026
CVE-2025-27773
CVE-2025-27773
Description
The SimpleSAMLphp SAML2 library is a PHP library for SAML2 related functionality. Prior to versions 4.17.0 and 5.0.0-alpha.20, there is a signature confusion attack in the HTTPRedirect binding. An attacker with any signed SAMLResponse via the HTTP-Redirect binding can cause the application to accept an unsigned message. Versions 4.17.0 and 5.0.0-alpha.20 contain a fix for the issue.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
simplesamlphp/saml2Packagist | < 4.17.0 | 4.17.0 |
simplesamlphp/saml2Packagist | >= 5.0.0-alpha.1, < 5.0.0-alpha.20 | 5.0.0-alpha.20 |
simplesamlphp/saml2-legacyPackagist | < 4.17.0 | 4.17.0 |
Patches
3bdf16d102136d35d41ba4b477867d6099dc7Merge commit from fork
2 files changed · +162 −11
src/Binding/HTTPRedirect.php+94 −11 modified@@ -123,14 +123,37 @@ public function send(AbstractMessage $message): ResponseInterface */ public function receive(ServerRequestInterface $request): AbstractMessage { - $query = $request->getQueryParams(); - - if (array_key_exists('SAMLRequest', $query)) { - $message = $query['SAMLRequest']; - $signedQuery = 'SAMLRequest=' . urlencode($query['SAMLRequest']); - } elseif (array_key_exists('SAMLResponse', $query)) { - $message = $query['SAMLResponse']; - $signedQuery = 'SAMLResponse=' . urlencode($query['SAMLResponse']); + $query = $this->parseQuery(); + $signedQuery = $query['SignedQuery']; + + /** + * Get the SAMLRequest/SAMLResponse from the exact same signed data that will be verified later in + * validateSignature into $res using the actual SignedQuery + */ + $res = []; + foreach (explode('&', $signedQuery) as $e) { + $tmp = explode('=', $e, 2); + $name = $tmp[0]; + if (count($tmp) === 2) { + $value = $tmp[1]; + } else { + /* No value for this parameter. */ + $value = ''; + } + $name = urldecode($name); + $res[$name] = urldecode($value); + } + + /** + * Put the SAMLRequest/SAMLResponse from the actual query string into $message, + * and assert that the result from parseQuery() in $query and the parsing of the SignedQuery in $res agree + */ + if (array_key_exists('SAMLRequest', $res)) { + Assert::same($res['SAMLRequest'], $query['SAMLRequest'], 'Parse failure.'); + $message = $res['SAMLRequest']; + } elseif (array_key_exists('SAMLResponse', $res)) { + Assert::same($res['SAMLResponse'], $query['SAMLResponse'], 'Parse failure.'); + $message = $res['SAMLResponse']; } else { throw new Exception('Missing SAMLRequest or SAMLResponse parameter.'); } @@ -154,7 +177,6 @@ public function receive(ServerRequestInterface $request): AbstractMessage $message = MessageFactory::fromXML($document->documentElement); if (array_key_exists('RelayState', $query)) { - $signedQuery .= '&RelayState=' . urlencode($query['RelayState']); $this->setRelayState($query['RelayState']); } @@ -174,8 +196,6 @@ public function receive(ServerRequestInterface $request): AbstractMessage if (!array_key_exists('SigAlg', $query)) { throw new Exception('Missing signature algorithm.'); - } else { - $signedQuery .= '&SigAlg=' . urlencode($query['SigAlg']); } $container = ContainerSingleton::getInstance(); @@ -192,4 +212,67 @@ public function receive(ServerRequestInterface $request): AbstractMessage return $message; } + + + /** + * Helper function to parse query data. + * + * This function returns the query string split into key=>value pairs. + * It also adds a new parameter, SignedQuery, which contains the data that is + * signed. + * + * @return array The query data that is signed. + * @throws \Exception + */ + private static function parseQuery() : array + { + /* + * Parse the query string. We need to do this ourself, so that we get access + * to the raw (urlencoded) values. This is required because different software + * can urlencode to different values. + */ + $data = []; + $relayState = ''; + $sigAlg = ''; + $sigQuery = ''; + + foreach (explode('&', $_SERVER['QUERY_STRING']) as $e) { + $tmp = explode('=', $e, 2); + $name = $tmp[0]; + if (count($tmp) === 2) { + $value = $tmp[1]; + } else { + /* No value for this parameter. */ + $value = ''; + } + + $name = urldecode($name); + // Prevent keys from being set more than once + if (array_key_exists($name, $data)) { + throw new Exception('Duplicate parameter.'); + } + $data[$name] = urldecode($value); + + switch ($name) { + case 'SAMLRequest': + case 'SAMLResponse': + $sigQuery = $name . '=' . $value; + break; + case 'RelayState': + $relayState = '&RelayState=' . $value; + break; + case 'SigAlg': + $sigAlg = '&SigAlg=' . $value; + break; + } + } + + if (array_key_exists('SAMLRequest', $data) && array_key_exists('SAMLResponse', $data)) { + throw new Exception('Both SAMLRequest and SAMLResponse provided.'); + } + + $data['SignedQuery'] = $sigQuery . $relayState . $sigAlg; + + return $data; + } }
tests/SAML2/Binding/HTTPRedirectTest.php+68 −0 modified@@ -63,6 +63,9 @@ public static function tearDownAfterClass(): void */ public function testRequestParsing(): void { + $qs = 'SAMLRequest=pVJNjxMxDP0ro9yn88FOtRu1lcpWiEoLVNvCgQtKE6eNlHGG2IHl35OZLmLZQy%2BcrNh%2Bz88vXpDq%2FSDXic%2F4CN8TEBdPvUeSU2EpUkQZFDmSqHogyVru1x8eZDur5RADBx28eAG5jlBEENkFFMV2sxTfzO0dmKa11namPuoc39hba%2BfqpqlbM6%2Fb5mZ%2B1LWtj6L4ApEycikyUYYTJdgisULOqbrpyqYt67tD28iulV33VRSbvI1DxRPqzDyQrCrAk0OYUYpWB4QnnqGvVN4fkJ2emitnhoocnjyU5E5YjnrXf6TfB6TUQ9xD%2FOE0fH58%2BEueHbHOv2Yn1w8eRneqPpiU68M5DxjfdIltqTRNWQNWJc8lDaLYPfv71qHJaq5be7w0kXx%2FOOzK3af9QawWI7ecrIqr%2F9HYAyujWL2SuKheDlhcbuljlrbd7IJ3%2BlfxLsRe8XXlY8aZ0k6tkqNCcvkzsuXeh5%2F3ERTDUnBMIKrVZeS%2FF7v6DQ%3D%3D'; + $_SERVER['QUERY_STRING'] = $qs; + $q = [ 'SAMLRequest' => 'pVJNjxMxDP0ro9yn88FOtRu1lcpWiEoLVNvCgQtKE6eNlHGG2IHl35OZLmLZQy+crNh+z88vXpDq/SDXic/4CN8TEBdPvUeSU2EpUkQZFDmSqHogyVru1x8eZDur5RADBx28eAG5jlBEENkFFMV2sxTfzO0dmKa11namPuoc39hba+fqpqlbM6/b5mZ+1LWtj6L4ApEycikyUYYTJdgisULOqbrpyqYt67tD28iulV33VRSbvI1DxRPqzDyQrCrAk0OYUYpWB4QnnqGvVN4fkJ2emitnhoocnjyU5E5YjnrXf6TfB6TUQ9xD/OE0fH58+EueHbHOv2Yn1w8eRneqPpiU68M5DxjfdIltqTRNWQNWJc8lDaLYPfv71qHJaq5be7w0kXx/OOzK3af9QawWI7ecrIqr/9HYAyujWL2SuKheDlhcbuljlrbd7IJ3+lfxLsRe8XXlY8aZ0k6tkqNCcvkzsuXeh5/3ERTDUnBMIKrVZeS/F7v6DQ==', ]; @@ -85,6 +88,9 @@ public function testRequestParsing(): void */ public function testResponseParsing(): void { + $qs = 'SAMLResponse=vVdbc6rIGn2fX2G5H1MJd0RrJ1UgKmDQIIiXl1NANzcRCA2i%2FvppNLpNJsnMnqo5T9qL%2Fq7r62bxEznbJO%2FNIMqzFMHWfpukqHcCH9tVkfYyB0WolzpbiHql1zNF%2FblHP5C9vMjKzMuS9o3J9xYOQrAooyxtt1T5sd2fzqxplxVIhoIMCbkuIEnehSRJ0xRJdroU1fFc6HWA4Hiw3bJhgbDtYxu7wg4QqqCaotJJSwyRFHdP0fcUb1Fsj2V7pLBut2SIyih1ypNVWJY56hFEGW6iexSBh7y8Z4WHqiweUFX4XpJV4CFNiC1Mkiwl8gyVl57gaOnlv5U9tv9HdzsSTQ4GlCB0hqQ8xD84XYHmOzxFMkOh%2FfSz6UbvlGTxdAkN0yBK4UOJ0zrHzFK4L5ugTlWGMC0j75QsEYEc51E6wCmdn8Stq59ntszSKSv0ftXPAGzZTlLB71lAp909s%2FI8iFCbeDpHeO%2B0J164emN3j6JzD3EddV0%2F1MxDVgQETZIUsdSfTS%2BEW%2Bc%2BOhHSsHWx%2Bnuj22HoMgwA0KV53GHKFQTHcR2PZT0SQEHgfAggECB0%2F8Uw%2FHeMANzLKMBjVhWX0wO%2BKpskyC6B9wAUBT%2FaT3%2B0WhdzCNTUz07e%2Bk6apThwEh1PwXVYhhloiUmQFVEZbr9sKUU2vu%2Fh3rv3KDb9gbnFEX7FOKX4D729y7RAzj0KHerssHE3gz4sIGa6NZ%2Bpj%2B0fv0ffqUyrcFLkZ8UWvV%2F%2BXmow3cEkyyHAZ%2Fqtwmakf8vhp537Sfw1RzkK8KT8mw6%2Bde%2BXk9NBfdou75YRhJU%2FUXO3XN7ZQjh2p%2FmwFsXHUwK3m0%2FAtfHn5YfRubJ8tuhXCeETSyl2wWg%2BX5aA3K4SL6ZhcjciFlLVCUcCKUOKMRcSuwfiRCIPSyXNd5bvktb%2BTkUvuwUi2CWnOgdt42XqgZ75x2dIB0p3bB61VyllUn4Z18mEu6P8TjGtzLkrBfOIOGp70Y6D9apEu1gJkklHFgVlM1TvFra%2FP2SvSubm0kE6slSaB%2FPHazk3%2Bf%2FR1DSGh2t9S47syvgIXhf95pLym1MKn3RV7d8d%2B31xawZirUpioGrii7Z7jg00m7GRLpKjvvk6MlWXkY2BJBlzUR%2BS%2B%2F5R1KRgYkviyhI3nK7PxFoOVrJtGOqgBjZQtGRFh%2BQNrnyBjzFu2bY2crc2xoN6eMblQd0l18sJqUfScbWgkDqaJF5q1EroTXRrXutHldQtA%2F8OmEWDxSdsf8ViCegGqvvGyd9oUGtTSx4YusiORGo%2B6Eu6Yi9nh%2FVikoEbXNp%2FjvdDXZlTtjnbcgnGV7q0OuHiXn8BI%2FsIZDXw6GHp9qV4vdRIXR35H%2Fsn4v5hdxNR7kuRMZYCo78fr4p0IUzqVzCrZ7WjVJjGZ74bGENLc4GfieZzuIog7U6jTDtoNeXfeeIuj1HCmvYq3w0QVGG5VITnIN90xh3mZSNrzwIYBiwaxMMhHwfbuJgOTCbbE0FpgS4g7PpFUYndi%2BqNDhRybY3NB%2Fow4YAwmorHTNtMFuAl7tY2W%2BzYasdwunMQalUWDVHKWKWPayN0iWzqB3JgLCTJslTnpc7HOSZYgKpuHiez9Tw2SzeKcUNqzMGMjCV1pGDbQfDd%2FtdhmA%2BFemkNnnVxc%2BYk1PvWpt4PZHF6nrvAkiib9LZ27CjGDe59gWcYn9jzzbpaL439SBYXZ1y3ZGaWeIxxUJVJ6C7qYEXbB6B%2BPAf1qdZBbQx1UZdEX6hlY6WNs7Ua7ryJaAyGkiHikR6IY2Gws%2Bbkc6BoyKzwhTeF22CW5LnuayKcbqtqPQlNfUUbYbUdTte5I7rCZKjW8%2FHcPhy01Mw6G35TKv2x2mWRgbodnmbp0JLl1aBeaHJXCUUkvk4zmpo7QrC2GIGotzwNmXFQjJe7NIlFd%2FyylJeazjqbY%2BfAK3y926kji%2FdJn4y0hfLKsHFdn2%2BQj5fCFTxfG8TthfLuxnkTCGblxtAr31YTrJ5UuTXEbwCn%2FF5WNUgE7v3T1l7ZvDgiLCDaT6TDsb7LdEm%2Bi2Uiw3DAYSDLkKxP%2BRzPOMDlXZ73%2BTdZcQ75Ppt%2BlvpR47fRY%2BfXz%2FfJeNueC50CFu2vHTUNaU2ycppOC9EvYfEX5dQ9y%2BgZ9KK8qeX%2FLKIvyvSz5D88eqsS7wBR8xg1hUkQkwE%2F04MdXNU%2FqPwihSsQNW9cnH1ZRN45%2FLsnT7%2FZlw9K8urmw%2FpdQOJDhdcUyjBtlDvcYoZap%2BVXSpjucRyu3MSyH3v4sgE03WOZHi382qqmAO4xZZwLuC5Pczzrk5zHeRTPAMahXExcx6V8yDGMA7sQeKB9mx5OusSy%2BhOon%2BBvQixpnr79bPR6XrMPwy%2F4p84KcG3UJ65%2BRbno9zRoVo1YO1yZwpIxxaL%2BwceHFj6k2Y3Hz8w%2BCfgOuzJwRS%2FfT9fPq8vwP%2F0J'; + $_SERVER['QUERY_STRING'] = $qs; + $q = [ 'SAMLResponse' => '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', ]; @@ -104,6 +110,9 @@ public function testResponseParsing(): void */ public function testRequestParsingMoreParams(): void { + $request = 'SAMLRequest=pVJNb9swDP0rhu6O7XjeGiEJkDYoGqDbgibboZdCkahEgEx5Ir11%2F36y02FdD7n0JPDjPT4%2BcU6q9Z1c9XzCB%2FjRA3H23HokORYWoo8ogyJHElULJFnL3erzvZxOStnFwEEHL15BLiMUEUR2AUW2WS%2FEUw2NrXRp7NWshEPVzJqm%2BTQzVV1DddC21rUy1tq6norsO0RKyIVIRAlO1MMGiRVySpVVk1fTvKr25ZVsGvnh46PI1mkbh4pH1Im5I1kUgEeHMKE%2BWh0QnnmCvlBpf0B2emwunOkKcnj0kJM7Yj7oXf2VfhOQ%2BhbiDuJPp%2BHbw%2F0%2F8uSIdf4tO7m28zC4U7TB9KnendKAIabzO82VpjFrwKrec06dyLYv%2Fl47NEnNZWsP5yaSd%2Fv9Nt9%2B3e3Fcj5wy9GquHyPxhZYGcXqjcR58XrA%2FHxLX5K0zXobvNO%2Fs9sQW8WXlQ8ZZ3I7tkqOCsmlz0iWex9%2B3URQDAvBsQdRLM8j%2F7%2FY5R8%3D&RelayState=https%3A%2F%2Fprofile.surfconext.nl%2F&SAMLEncoding=urn%3Aoasis%3Anames%3Atc%3ASAML%3A2.0%3Abindings%3AURL-Encoding%3ADEFLATE'; + $_SERVER['QUERY_STRING'] = $request; + $q = [ 'SAMLRequest' => 'pVJNb9swDP0rhu6O7XjeGiEJkDYoGqDbgibboZdCkahEgEx5Ir11/36y02FdD7n0JPDjPT4+cU6q9Z1c9XzCB/jRA3H23HokORYWoo8ogyJHElULJFnL3erzvZxOStnFwEEHL15BLiMUEUR2AUW2WS/EUw2NrXRp7NWshEPVzJqm+TQzVV1DddC21rUy1tq6norsO0RKyIVIRAlO1MMGiRVySpVVk1fTvKr25ZVsGvnh46PI1mkbh4pH1Im5I1kUgEeHMKE+Wh0QnnmCvlBpf0B2emwunOkKcnj0kJM7Yj7oXf2VfhOQ+hbiDuJPp+Hbw/0/8uSIdf4tO7m28zC4U7TB9KnendKAIabzO82VpjFrwKrec06dyLYv/l47NEnNZWsP5yaSd/v9Nt9+3e3Fcj5wy9GquHyPxhZYGcXqjcR58XrA/HxLX5K0zXobvNO/s9sQW8WXlQ8ZZ3I7tkqOCsmlz0iWex9+3URQDAvBsQdRLM8j/7/Y5R8=', 'RelayState' => 'https://profile.surfconext.nl/', @@ -126,6 +135,9 @@ public function testRequestParsingMoreParams(): void */ public function testSignedRequestParsing(): void { + $qs = 'SAMLRequest=hVLLbttADPwVYe%2BylJXsyAvbgBujqIG0MWK3h1wCVkvFC%2BxDXVJp%2B%2FddywmS9uCeCJAznOGACwJne7Ue%2BOjv8ceAxNkvZz2pcbAUQ%2FQqABlSHhyS4lbt159vlZyUqo%2BBQxuseEe5zAAijGyCF9l2sxSPjZ41jW5npZxjpWvsrisoZ9ddV8NU6is5nTczXTfTeS2ybxgpMZciLUp0ogG3nhg8p1Ypq7y8ymV1kJUqa1XJB5Ft0jXGA4%2BsI3NPqiiM7icuhBxiezTPOPG2cEEPFif9sS9OJ5wgBRn%2FZHFvnvyd32N8Ni2KbP1q%2FyZ4GhzGl8nX%2B9s3AY0u%2FE%2BBzlXm0NLY1djBYDmnXmS7l1g%2FGK%2BTi8uJfj%2BDSH06HHb57m5%2FEKvFabcaE4qrV1v%2FOEoOHDJoYFgU7%2FGL80d8SUrbzS5Y0%2F7OPobogC8bOXWMzrsRqjiCJ4OeU2jWhp83EYFxKTgOKIrVWfLvv1v9AQ%3D%3D&RelayState=https%3A%2F%2Fdemo.moo-archive.nl%2Fmodule.php%2Fadmin%2Ftest%2Fdefault-sp&SigAlg=http%3A%2F%2Fwww.w3.org%2F2001%2F04%2Fxmldsig-more%23rsa-sha256&Signature=T8%2BSG10HcgOkpw4cUFTnoF9WWrlYnllnqKruvmVcyinbiJsdnw7EMxM6Lr%2F5Mo%2FRk3Hd7x8tuQ955Vv96jMRKGfdvq8Dh1gx4PKJPHXFWBSipWOc9UDNT0N3addnk9PiSaQ5YehT9lZ4agoSmKqiWNrE4qpKIcgWdh0GgiYDUto%3D'; + $_SERVER['QUERY_STRING'] = $qs; + $q = [ 'SAMLRequest' => 'hVLLbttADPwVYe+ylJXsyAvbgBujqIG0MWK3h1wCVkvFC+xDXVJp+/ddywmS9uCeCJAznOGACwJne7Ue+Ojv8ceAxNkvZz2pcbAUQ/QqABlSHhyS4lbt159vlZyUqo+BQxuseEe5zAAijGyCF9l2sxSPjZ41jW5npZxjpWvsrisoZ9ddV8NU6is5nTczXTfTeS2ybxgpMZciLUp0ogG3nhg8p1Ypq7y8ymV1kJUqa1XJB5Ft0jXGA4+sI3NPqiiM7icuhBxiezTPOPG2cEEPFif9sS9OJ5wgBRn/ZHFvnvyd32N8Ni2KbP1q/yZ4GhzGl8nX+9s3AY0u/E+BzlXm0NLY1djBYDmnXmS7l1g/GK+Ti8uJfj+DSH06HHb57m5/EKvFabcaE4qrV1v/OEoOHDJoYFgU7/GL80d8SUrbzS5Y0/7OPobogC8bOXWMzrsRqjiCJ4OeU2jWhp83EYFxKTgOKIrVWfLvv1v9AQ==', 'RelayState' => 'https://demo.moo-archive.nl/module.php/admin/test/default-sp', @@ -151,6 +163,9 @@ public function testSignedRequestParsing(): void */ public function testSignedRequestValidation(): void { + $qs = 'SAMLRequest=hVLLbttADPwVYe%2BylJXsyAvbgBujqIG0MWK3h1wCVkvFC%2BxDXVJp%2B%2FddywmS9uCeCJAznOGACwJne7Ue%2BOjv8ceAxNkvZz2pcbAUQ%2FQqABlSHhyS4lbt159vlZyUqo%2BBQxuseEe5zAAijGyCF9l2sxSPjZ41jW5npZxjpWvsrisoZ9ddV8NU6is5nTczXTfTeS2ybxgpMZciLUp0ogG3nhg8p1Ypq7y8ymV1kJUqa1XJB5Ft0jXGA4%2BsI3NPqiiM7icuhBxiezTPOPG2cEEPFif9sS9OJ5wgBRn%2FZHFvnvyd32N8Ni2KbP1q%2FyZ4GhzGl8nX%2B9s3AY0u%2FE%2BBzlXm0NLY1djBYDmnXmS7l1g%2FGK%2BTi8uJfj%2BDSH06HHb57m5%2FEKvFabcaE4qrV1v%2FOEoOHDJoYFgU7%2FGL80d8SUrbzS5Y0%2F7OPobogC8bOXWMzrsRqjiCJ4OeU2jWhp83EYFxKTgOKIrVWfLvv1v9AQ%3D%3D&RelayState=https%3A%2F%2Fdemo.moo-archive.nl%2Fmodule.php%2Fadmin%2Ftest%2Fdefault-sp&SigAlg=http%3A%2F%2Fwww.w3.org%2F2001%2F04%2Fxmldsig-more%23rsa-sha256&Signature=T8%2BSG10HcgOkpw4cUFTnoF9WWrlYnllnqKruvmVcyinbiJsdnw7EMxM6Lr%2F5Mo%2FRk3Hd7x8tuQ955Vv96jMRKGfdvq8Dh1gx4PKJPHXFWBSipWOc9UDNT0N3addnk9PiSaQ5YehT9lZ4agoSmKqiWNrE4qpKIcgWdh0GgiYDUto%3D'; + $_SERVER['QUERY_STRING'] = $qs; + $q = [ 'SAMLRequest' => 'hVLLbttADPwVYe+ylJXsyAvbgBujqIG0MWK3h1wCVkvFC+xDXVJp+/ddywmS9uCeCJAznOGACwJne7Ue+Ojv8ceAxNkvZz2pcbAUQ/QqABlSHhyS4lbt159vlZyUqo+BQxuseEe5zAAijGyCF9l2sxSPjZ41jW5npZxjpWvsrisoZ9ddV8NU6is5nTczXTfTeS2ybxgpMZciLUp0ogG3nhg8p1Ypq7y8ymV1kJUqa1XJB5Ft0jXGA4+sI3NPqiiM7icuhBxiezTPOPG2cEEPFif9sS9OJ5wgBRn/ZHFvnvyd32N8Ni2KbP1q/yZ4GhzGl8nX+9s3AY0u/E+BzlXm0NLY1djBYDmnXmS7l1g/GK+Ti8uJfj+DSH06HHb57m5/EKvFabcaE4qrV1v/OEoOHDJoYFgU7/GL80d8SUrbzS5Y0/7OPobogC8bOXWMzrsRqjiCJ4OeU2jWhp83EYFxKTgOKIrVWfLvv1v9AQ==', 'RelayState' => 'https://demo.moo-archive.nl/module.php/admin/test/default-sp', @@ -218,6 +233,9 @@ public function testSignedRequestValidationWrongKeytype(): void */ public function testInvalidEncodingSpecified(): void { + $qs = 'SAMLRequest=pVJNb9swDP0rhu6O7XjeGiEJkDYoGqDbgibboZdCkahEgEx5Ir11%2F36y02FdD7n0JPDjPT4%2BcU6q9Z1c9XzCB%2FjRA3H23HokORYWoo8ogyJHElULJFnL3erzvZxOStnFwEEHL15BLiMUEUR2AUW2WS%2FEUw2NrXRp7NWshEPVzJqm%2BTQzVV1DddC21rUy1tq6norsO0RKyIVIRAlO1MMGiRVySpVVk1fTvKr25ZVsGvnh46PI1mkbh4pH1Im5I1kUgEeHMKE%2BWh0QnnmCvlBpf0B2emwunOkKcnj0kJM7Yj7oXf2VfhOQ%2BhbiDuJPp%2BHbw%2F0%2F8uSIdf4tO7m28zC4U7TB9KnendKAIabzO82VpjFrwKrec06dyLYv%2Fl47NEnNZWsP5yaSd%2Fv9Nt9%2B3e3Fcj5wy9GquHyPxhZYGcXqjcR58XrA%2FHxLX5K0zXobvNO%2Fs9sQW8WXlQ8ZZ3I7tkqOCsmlz0iWex9%2B3URQDAvBsQdRLM8j%2F7%2FY5R8%3D&RelayState=https%3A%2F%2Fprofile.surfconext.nl%2F&SAMLEncoding=urn%3Aoasis%3Anames%3Atc%3ASAML%3A2.0%3Abindings%3AURL-Encoding%3Anone'; + $_SERVER['QUERY_STRING'] = $qs; + $q = [ 'SAMLRequest' => 'pVJNb9swDP0rhu6O7XjeGiEJkDYoGqDbgibboZdCkahEgEx5Ir11%2F36y02FdD7n0JPDjPT4%2BcU6q9Z1c9XzCB%2FjRA3H23HokORYWoo8ogyJHElULJFnL3erzvZxOStnFwEEHL15BLiMUEUR2AUW2WS%2FEUw2NrXRp7NWshEPVzJqm%2BTQzVV1DddC21rUy1tq6norsO0RKyIVIRAlO1MMGiRVySpVVk1fTvKr25ZVsGvnh46PI1mkbh4pH1Im5I1kUgEeHMKE%2BWh0QnnmCvlBpf0B2emwunOkKcnj0kJM7Yj7oXf2VfhOQ%2BhbiDuJPp%2BHbw%2F0%2F8uSIdf4tO7m28zC4U7TB9KnendKAIabzO82VpjFrwKrec06dyLYv%2Fl47NEnNZWsP5yaSd%2Fv9Nt9%2B3e3Fcj5wy9GquHyPxhZYGcXqjcR58XrA%2FHxLX5K0zXobvNO%2Fs9sQW8WXlQ8ZZ3I7tkqOCsmlz0iWex9%2B3URQDAvBsQdRLM8j%2F7%2FY5R8%3D', 'RelayState' => 'https://profile.surfconext.nl/', @@ -237,6 +255,9 @@ public function testInvalidEncodingSpecified(): void */ public function testNoSigAlgSpecified(): void { + $qs = 'SAMLRequest=nVLBauMwEP0Vo7sjW7FpKpJA2rBsoNuGOruHXhZFHm8EsuRqxtv27yvbWWgvYelFgjfvzbx5zBJVazu56enkHuG5B6TktbUO5VhYsT446RUalE61gJK0rDY%2F7qSYZbILnrz2ln2QXFYoRAhkvGPJbrtiv7VoygJEoTJ9LOusXDSFuJ4vdH6cxwoIEGUjsrqoFUt%2BQcCoXLHYKMoRe9g5JOUoQlleprlI8%2FyQz6W4ksXiiSXbuI1xikbViahDyfkRSM2wD40DmjnL0bSdhcE6Hx7BTd3xqnqoIPw1GmbdqWPJNx80jCGtGIUeWLL5t8mtd9i3EM78n493%2FzWr9XVvx%2B58mj39IlUaR%2FQmKOPq4Dtkyf4c9E1EjPtzOePjREL5%2FXDYp%2FuH6sDWy6G3HDML66%2B5ayO7VlHx2dySf2y9nM7pPprabffeGv02ZNcquux5QEydNiNVUlAODTiKMVvrX24DKIJz8nw9jfx8tOt3&RelayState=https%3A%2F%2Fbeta.surfnet.nl%2Fsimplesaml%2Fmodule.php%2Fcore%2Fauthenticate.php%3Fas%3DBraindrops&Signature=b%2Bqe%2FXGgICOrEL1v9dwuoy0RJtJ%2FGNAr7gJGYSJzLG0riPKwo7v5CH8GPC2P9IRikaeaNeQrnhBAaf8FCWrO0cLFw4qR6msK9bxRBGk%2BhIaTUYCh54ETrVCyGlmBneMgC5%2FiCRvtEW3ESPXCCqt8Ncu98yZmv9LIVyHSl67Se%2BfbB9sDw3%2FfzwYIHRMqK2aS8jnsnqlgnBGGOXqIqN3%2Bd%2F2dwtCfz14s%2F9odoYzSUv32qfNPiPez6PSNqwhwH7dWE3TlO%2FjZmz0DnOeQ2ft6qdZEi5ZN5KCV6VmNKpkrLMq6DDPnuwPm%2F8oCAoT88R2jG7uf9QZB%2BArWJKMEhDLsCA%3D%3D'; + $_SERVER['QUERY_STRING'] = $qs; + $q = [ 'SAMLRequest' => 'nVLBauMwEP0Vo7sjW7FpKpJA2rBsoNuGOruHXhZFHm8EsuRqxtv27yvbWWgvYelFgjfvzbx5zBJVazu56enkHuG5B6TktbUO5VhYsT446RUalE61gJK0rDY/7qSYZbILnrz2ln2QXFYoRAhkvGPJbrtiv7VoygJEoTJ9LOusXDSFuJ4vdH6cxwoIEGUjsrqoFUt+QcCoXLHYKMoRe9g5JOUoQlleprlI8/yQz6W4ksXiiSXbuI1xikbViahDyfkRSM2wD40DmjnL0bSdhcE6Hx7BTd3xqnqoIPw1GmbdqWPJNx80jCGtGIUeWLL5t8mtd9i3EM78n493/zWr9XVvx+58mj39IlUaR/QmKOPq4Dtkyf4c9E1EjPtzOePjREL5/XDYp/uH6sDWy6G3HDML66+5ayO7VlHx2dySf2y9nM7pPprabffeGv02ZNcquux5QEydNiNVUlAODTiKMVvrX24DKIJz8nw9jfx8tOt3', 'RelayState' => 'https://beta.surfnet.nl/simplesaml/module.php/core/authenticate.php?as=Braindrops', @@ -257,6 +278,9 @@ public function testNoSigAlgSpecified(): void */ public function testInvalidRequestData(): void { + $qs = 'SAMLRequest=cannotinflate'; + $_SERVER['QUERY_STRING'] = $qs; + $q = ['SAMLRequest' => 'cannotinflate']; $request = new ServerRequest('GET', 'http://tnyholm.se'); $request = $request->withQueryParams($q); @@ -273,6 +297,9 @@ public function testInvalidRequestData(): void */ public function testNoRequestOrResponse(): void { + $qs = 'aap=noot&mies=jet&wim&RelayState=etc'; + $_SERVER['QUERY_STRING'] = $qs; + $q = ['aap' => 'noot', 'mies' => 'jet&wim', 'RelayState' => 'etc']; $request = new ServerRequest('GET', 'http://tnyholm.se'); $request = $request->withQueryParams($q); @@ -347,4 +374,45 @@ public function testSendAuthnResponseBespokeDestination(): void $hr->setDestination('gopher://myurl'); $hr->send($response); } + + + /** + * Test that multiple query parameters with the same name are not allowed. + * + */ + public function testDuplicateQueryParameters(): void + { + $q = ['SAMLRequest' => 'noot', 'SAMLRequest' => 'jet&wim', 'RelayState' => 'etc']; + $request = new ServerRequest('GET', 'http://tnyholm.se'); + $request = $request->withQueryParams($q); + + // SAMLRequest appears twice + $qs = 'SAMLRequest=first&RelayState=somestate&SAMLRequest=second&Signature=sig&&SigAlg=alg'; + $_SERVER['QUERY_STRING'] = $qs; + + $this->expectException(Exception::class); + $this->expectExceptionMessage('Duplicate parameter.'); + $hr = new HTTPRedirect(); + $hr->receive($request); + } + + + /** + * Test that providing both SAMLRequest and SAMLResponse is not allowed + */ + public function testSAMLResponseAndSAMLRequestConfusion(): void + { + $q = ['SAMLRequest' => 'noot', 'SAMLResponse' => 'jet&wim', 'RelayState' => 'etc']; + $request = new ServerRequest('GET', 'http://tnyholm.se'); + $request = $request->withQueryParams($q); + + // Both SAMLRequest and SAML Response appear + $qs = 'SAMLRequest=first&RelayState=somestate&SAMLResponse=second&Signature=sig&&SigAlg=alg'; + $_SERVER['QUERY_STRING'] = $qs; + + $this->expectException(Exception::class); + $this->expectExceptionMessage('Both SAMLRequest and SAMLResponse provided.'); + $hr = new HTTPRedirect(); + $hr->receive($request); + } }
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
7- github.com/advisories/GHSA-46r4-f8gj-xg56ghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2025-27773ghsaADVISORY
- github.com/simplesamlphp/saml2/blob/9545abd0d9d48388f2fa00469c5c1e0294f0303e/src/SAML2/HTTPRedirect.phpnvdWEB
- github.com/simplesamlphp/saml2/blob/9545abd0d9d48388f2fa00469c5c1e0294f0303e/src/SAML2/HTTPRedirect.phpnvdWEB
- github.com/simplesamlphp/saml2/commit/7867d6099dc7f31bed1ea10e5bea159c5623d2a0nvdWEB
- github.com/simplesamlphp/saml2/security/advisories/GHSA-46r4-f8gj-xg56nvdWEB
- lists.debian.org/debian-lts-announce/2025/05/msg00013.htmlnvdWEB
News mentions
0No linked articles in our index yet.