CVE-2023-40178 (published 2023-08-23T21:15Z)

Node-SAML is a SAML library not dependent on any frameworks that runs in Node. The lack of checking of current timestamp allows a LogoutRequest XML to be reused multiple times even when the current time is past the NotOnOrAfter. This could impact the user where they would be logged out from an expired LogoutRequest. In bigger contexts, if LogoutRequests are sent out in mass to different SPs, this could impact many users on a large scale. This issue was patched in version 4.0.5.\n

CVSS v3 base score: 5.3, MEDIUM (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L)

Weakness information:
cwe_id: CWE-613
cwe_name: Insufficient Session Expiration
description: According to WASC, "Insufficient Session Expiration is when a web site permits an attacker to reuse old session credentials or session IDs for authorization."
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: jindazhao01
author_date: 2023-08-18 11:07:34-07:00
msg: Merge pull request from GHSA-vx8m-6fhw-pccw

* Added verifyLogoutRequest to validatePostRequestAsync flow

* Added bad expiration test

* Updated IssueInstance to be in the past
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: @@ -1265,6 +1265,7 @@ class SAML {
     dom: Document,
   ): Promise<{ profile: Profile; loggedOut: boolean }> {
     const request = doc.LogoutRequest;
+    this.verifyLogoutRequest(doc);
     if (request) {
       const profile = {} as Profile;
       if (request.$.ID) {

programming_language: TypeScript
filename: logout_request_with_bad_expiration.xml
change_type: ModificationType.ADD
diff: @@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<saml2p:LogoutRequest xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol" Destination="http://idp.example.com/SingleLogoutService.php" ID="pfxd4d369e8-9ea1-780c-aff8-a1d11a9862a1" IssueInstant="2013-08-17T22:17:51.000Z" NotOnOrAfter="2022-08-17T22:17:51.000Z" Version="2.0">
+    <saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">http://sp.example.com/demo1/metadata.php</saml2:Issuer>
+<saml2:NameID xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">test@email.com</saml2:NameID>
+    <saml2p:SessionIndex>_P230330115104244DUB9FUDV49NSOB5</saml2p:SessionIndex>
+<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="#pfxd4d369e8-9ea1-780c-aff8-a1d11a9862a1"><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>26LYQJFuGaMg9xdZLo+6J118KHU=</DigestValue></Reference></SignedInfo><SignatureValue>OTzlyaL0HDLLC9xLgwctQhHB5hthWjmnVho6g7p8e5m84c4J+/08GLaC8/Iz/cqXcoxU32PZr3MLnPAqEY2RwfCIldhMyXmRdVRi4DkiXmOmhw+tzgbXo6kGe+28rTSnXJ7L97NkX48T83bsfGZ+LAdEHe9ZQUL+vWZYXwn7xVagiTJ1YjfUO44UVdTelAJ9kQKQcIjW7A6WafyYqC7dqahvGsgYJ4o4grBkaP+PxfJ5vwuTW0qkjLH7wcLRfpJDeCiWwdNr9W6TgV8C8qJ0fDtl5xfYvSPmbDViXA89TQhu9uCu7tJQpjCeCv1hAO7igj2TbP87QNTyOhseNKpzKA==</SignatureValue><KeyInfo><X509Data/></KeyInfo></Signature></saml2p:LogoutRequest>
\ No newline at end of file

programming_language: Markdown
filename: tests.spec.ts
change_type: ModificationType.MODIFY
diff: @@ -2847,6 +2847,18 @@ describe("node-saml /", function () {
       });
     });
 
+    it("errors if expired", async () => {
+      const body = {
+        SAMLRequest: fs.readFileSync(
+          __dirname + "/static/logout_request_with_bad_expiration.xml",
+          "base64",
+        ),
+      };
+      await assert.rejects(samlObj.validatePostRequestAsync(body), {
+        message: "SAML assertion expired: clocks skewed too much",
+      });
+    });
+
     it("returns profile for valid signature", async () => {
       const body = {
         SAMLRequest: fs.readFileSync(

programming_language: JavaScript