CVE-2022-39300 (published 2022-10-13T22:15Z)

node SAML is a SAML 2.0 library based on the SAML implementation of passport-saml. A remote attacker may be able to bypass SAML authentication on a website using passport-saml. A successful attack requires that the attacker is in possession of an arbitrary IDP signed XML element. Depending on the IDP used, fully unauthenticated attacks (e.g without access to a valid user) might also be feasible if generation of a signed message can be triggered. Users should upgrade to node-saml version 4.0.0-beta5 or newer. Disabling SAML authentication may be done as a workaround.

CVSS v3 base score: 8.1, HIGH (CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H)

Weakness information:
cwe_id: CWE-347
cwe_name: Improper Verification of Cryptographic Signature
description: The product does not verify, or incorrectly verifies, the cryptographic signature for data.
extended_description: 
            
            
         
         

Fix information:
repo_url: https://github.com/node-saml/node-saml
commit_details: repo_url: https://github.com/node-saml/node-saml
author: Chris Barth
author_date: 2022-10-11 13:21:18-04:00
msg: Merge pull request from GHSA-5p8w-2mvw-38pv
repository: repo_url: https://github.com/node-saml/node-saml
repo_name: node-saml/node-saml
description: A SAML library not dependent on any frameworks that runs in Node.
repo_language: TypeScript
owner: node-saml
file_changes: filename: saml.ts
change_type: ModificationType.MODIFY
diff: @@ -688,9 +688,14 @@ class SAML {
         await this.validateInResponseTo(inResponseTo);
       }
       const certs = await this.certsToCheck();
-      // Check if this document has a valid top-level signature
+      // Check if this document has a valid top-level signature which applies to the entire XML document
       let validSignature = false;
-      if (validateSignature(xml, doc.documentElement, certs)) {
+      if (
+        validateSignature(xml, doc.documentElement, certs) &&
+        Array.from(doc.childNodes as NodeListOf<Element>).filter(
+          (n) => n.tagName != null && n.childNodes != null
+        ).length === 1
+      ) {
         validSignature = true;
       }
 

programming_language: TypeScript
filename: response.root-signed.multiple-root-elements.xml
change_type: ModificationType.ADD
diff: @@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<samlp:Response xmlns="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" ID="IDVALUE" Version="2.0" IssueInstant="2004-10-08T14:38:05Z">
+  <samlp:Status>
+    <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Responder">
+      <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:NoPassive">
+        <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:PartialLogout">
+        </samlp:StatusCode>
+      </samlp:StatusCode>
+    </samlp:StatusCode>
+    <samlp:StatusMessage>Random Error</samlp:StatusMessage>
+  </samlp:Status>
+  <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
+  <SignedInfo>
+    <CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
+    <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
+    <Reference URI="#IDVALUE">
+      <Transforms>
+        <Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
+        <Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
+      </Transforms>
+      <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
+      <DigestValue>sy2JL707GPx1uvsGKrALB+MVPek=</DigestValue>
+    </Reference>
+    </SignedInfo>
+  <SignatureValue>N4Pvot/wDRMmSdtp9XWJpK5krnSr9SZP7Ejeal8HaqZcjGXkYd35RJEiM69lHOI+
+80vrtr1pKokvHHh/iAmZr5daqKofmy70RAzt2SfxWyjkT46nkJpJ4R2MraJvrEjR
+qqwWKLwuPl6V64STUwId4DRpZyDt3u1+aaw0i0RaiQV6nKSXj1ODs3/OTehxtBbs
+Ok6kr03Z7lDu0Wv8qmJhwyMg1G+usW+hFdJZkpjzucSyGP2eVgJT7JvayVHlF/Se
+eT65266iWLE2kImImPpcw0HSVWKdOGR1EQNzGGtmYk/PjbyVmBfHZodvQm/EqT8q
+8Gxd+AmAINfG0Uvrm7p6dw==</SignatureValue>
+  <KeyInfo>
+    <X509Data>
+<X509Certificate>MIIDtTCCAp2gAwIBAgIJAKg4VeVcIDz1MA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV
+BAYTAlVTMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX
+aWRnaXRzIFB0eSBMdGQwHhcNMTUwODEzMDE1NDIwWhcNMTUwOTEyMDE1NDIwWjBF
+MQswCQYDVQQGEwJVUzETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50
+ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
+CgKCAQEAxG3ouM7U+fXbJt69X1H6d4UNg/uRr06pFuU9RkfIwNC+yaXyptqB3ynX
+KsL7BFt4DCd0fflRvJAx3feJIDp16wN9GDVHcufWMYPhh2j5HcTW/j9JoIJzGhJy
+vO00YKBt+hHy83iN1SdChKv5y0iSyiPP5GnqFw+ayyHoM6hSO0PqBou1Xb0ZSIE+
+DHosBnvVna5w2AiPY4xrJl9yZHZ4Q7DfMiYTgstjETio4bX+6oLiBnYktn7DjdEs
+lqhffVme4PuBxNojI+uCeg/sn4QVLd/iogMJfDWNuLD8326Mi/FE9cCRvFlvAiMS
+aebMI3zPaySsxTK7Zgj5TpEbmbHI9wIDAQABo4GnMIGkMB0GA1UdDgQWBBSVGgvo
+W4MhMuzBGce29PY8vSzHFzB1BgNVHSMEbjBsgBSVGgvoW4MhMuzBGce29PY8vSzH
+F6FJpEcwRTELMAkGA1UEBhMCVVMxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNV
+BAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZIIJAKg4VeVcIDz1MAwGA1UdEwQF
+MAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAJu1rqs+anD74dbdwgd3CnqnQsQDJiEX
+mBhG2leaGt3ve9b/9gKaJg2pyb2NyppDe1uLqh6nNXDuzg1oNZrPz5pJL/eCXPl7
+FhxhMUi04TtLf8LeNTCIWYZiFuO4pmhohHcv8kRvYR1+6SkLTC8j/TZerm7qvesS
+iTQFNapa1eNdVQ8nFwVkEtWl+JzKEM1BlRcn42sjJkijeFp7DpI7pU+PnYeiaXpR
+v5pJo8ogM1iFxN+SnfEs0EuQ7fhKIG9aHKi7bKZ7L6SyX7MDIGLeulEU6lf5D9Bf
+XNmcMambiS0pXhL2QXajt96UBq8FT2KNXY8XNtR4y6MyyCzhaiZZcc8=</X509Certificate>
+</X509Data>
+  </KeyInfo>
+</Signature>
+</samlp:Response>
+<Response>
+<saml:Assertion ID="_bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" IssueInstant="2020-09-25T16:00:00+00:00" Version="2.0">
+        <saml:Issuer>https://evil-corp.com</saml:Issuer>
+        <saml:Subject>
+            <saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress">vincent.vega@evil-corp.com
+            </saml:NameID>
+            <saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
+                <saml:SubjectConfirmationData InResponseTo="_e8df3fe5f04237d25670" NotOnOrAfter="2020-09-25T17:00:00+00:00" Recipient="https://evil-corp.madness.com/sso/callback"/>
+            </saml:SubjectConfirmation>
+        </saml:Subject>
+        <saml:Conditions NotBefore="2020-09-25T16:00:00+00:00" NotOnOrAfter="2020-09-25T17:00:00+00:00"/>
+        <saml:AuthnStatement AuthnInstant="2020-09-25T16:00:00+00:00" SessionIndex="_9e315bdf7b1b6732be33c377cf6f5c4f">
+            <saml:AuthnContext>
+                <saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport
+                </saml:AuthnContextClassRef>
+            </saml:AuthnContext>
+        </saml:AuthnStatement>
+        <saml:AttributeStatement>
+            <saml:Attribute Name="evil-corp.egroupid">
+                <saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">
+                    vincent.vega@evil-corp.com
+                </saml:AttributeValue>
+            </saml:Attribute>
+            <saml:Attribute Name="evilcorp.givenname">
+                <saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">Vincent
+                </saml:AttributeValue>
+            </saml:Attribute>
+            <saml:Attribute Name="evilcorp.sn">
+                <saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">VEGA
+                </saml:AttributeValue>
+            </saml:Attribute>
+        </saml:AttributeStatement>
+    </saml:Assertion>
+  </Response>
\ No newline at end of file

programming_language: PowerShell
filename: test-signatures.spec.ts
change_type: ModificationType.MODIFY
diff: @@ -67,6 +67,17 @@ describe("Signatures", function () {
       );
   };
 
+  describe("Signatures - multiple roots are considered invalid", () => {
+    it(
+      "multiple roots => invalid",
+      testOneResponse(
+        "/invalid/response.root-signed.multiple-root-elements.xml",
+        INVALID_DOCUMENT_SIGNATURE,
+        1
+      )
+    );
+  });
+
   describe("Signatures on saml:Response - Only 1 saml:Assertion", () => {
     let fakeClock: sinon.SinonFakeTimers;
 

programming_language: JavaScript