GHSA-fjr2-r2mp-484p: SimpleSAMLphp signature validation bypass
A signature validation bypass issue has been found in the SimpleSAML_XML_Validator
class. This class performs the verification of the XML digital signature of a SAML 1 message with a given key.
When a SAML 1 authentication response message is received, it is processed to verify its authenticity, including a check for the signature or signatures included in the message. If the message is not signed but the assertions contained in it are, the signatures of those assertions signed will be verified. Unsigned assertions will not be verified. After verifying every signed element in the response, a list of valid nodes is built, holding the DOM nodes of those XML elements that are signed and whose signatures have been successfully verified.
Once this list is built, the assertions need to be processed individually. They are not processed until the getAttributes() method of the SimpleSAML_XML_Shib13_AuthnResponse class is called. This method iterates through the list of assertions contained in the response and makes sure they were validated in the previous signature verification step, by checking if their corresponding DOM nodes are in the list of those verified.
The vulnerability is due to lax comparison of the node being checked and the nodes in the verified list. The isNodeValidated() method of the SimpleSAML_XML_Validator class checks if a given DOM node is in the validNodes array by means of the standard in_array() function. This function, however, will return unexpected results due to the default lax behaviour when checking data types in PHP. In this case, the fact that there is a DOM node in the list is enough for in_array() to return true when looking for any DOM node. This means any unsigned assertion will be considered verified if there is at least one assertion with a valid signature in the message being processed.
This issue allows an attacker to generate a SAML 1 authentication response that contains two different assertions. The first assertion is the one the attacker wants the Service Provider to use, with custom attributes, expiration and even entityID (provided that the given entityID belongs to an Identity Provider that the Service Provider knows and trusts). The second is a legitimate assertion issued and signed by an Identity Provider trusted by the Service Provider. If the second assertion is still valid when sent by the attacker, SimpleSAMLphp will merge all the attributes found in both assertions, but the entityID registered for the authenticating third-party will be the one found in the first, tampered assertion. If the second (legitimate) assertion is already expired when the attacker sends it, only the attributes found in the tampered assertion will be used.
The issue can be easily fixed by passing a third parameter to the in_array() function, telling it to perform strict comparisons when checking if an object is found inside a given array. This way, when the code evaluates if the tampered assertion is included in the list of verified assertions, it fails and only the legitimate assertion is used, if possible (e.g. it is not expired).
References
Detect and mitigate GHSA-fjr2-r2mp-484p with GitLab Dependency Scanning
Secure your software supply chain by verifying that all open source dependencies used in your projects contain no disclosed vulnerabilities. Learn more about Dependency Scanning →