CVE-2022-24794 (published 2022-03-31T23:15Z)

Express OpenID Connect is an Express JS middleware implementing sign on for Express web apps using OpenID Connect. Users of the `requiresAuth` middleware, either directly or through the default `authRequired` option, are vulnerable to an Open Redirect when the middleware is applied to a catch all route. If all routes under `example.com` are protected with the `requiresAuth` middleware, a visit to `http://example.com//google.com` will be redirected to `google.com` after login because the original url reported by the Express framework is not properly sanitized. This vulnerability affects versions prior to 2.7.2. Users are advised to upgrade. There are no known workarounds.

Severity: MEDIUM
CVSS v2 base score: 5.8 (AV:N/AC:M/Au:N/C:P/I:P/A:N)
CVSS v3 base score: 6.1, MEDIUM (CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N)

Weakness information:
cwe_id: CWE-601
cwe_name: URL Redirection to Untrusted Site ('Open Redirect')
description: A web application accepts a user-controlled input that specifies a link to an external site, and uses that link in a Redirect. This simplifies phishing attacks.
extended_description: An http parameter may contain a URL value and could cause the web application to redirect the request to the specified URL. By modifying the URL value to a malicious site, an attacker may successfully launch a phishing scam and steal user credentials. Because the server name in the modified link is identical to the original site, phishing attempts have a more trustworthy appearance. Whether this issue poses a vulnerability will be subject to the intended behavior of the application. For example, a search engine might intentionally provide redirects to arbitrary URLs.
         

Fix information:
repo_url: https://github.com/auth0/express-openid-connect
commit_details: repo_url: https://github.com/auth0/express-openid-connect
author: Adam Mcgrath
author_date: 2022-03-29 12:11:14+01:00
msg: Merge pull request from GHSA-7p99-3798-f85c
repository: repo_url: https://github.com/auth0/express-openid-connect
repo_name: auth0/express-openid-connect
description: An Express.js middleware to protect OpenID Connect web applications.
repo_language: JavaScript
owner: auth0
file_changes: filename: context.js
change_type: ModificationType.MODIFY
diff: @@ -187,7 +187,8 @@ class ResponseContext {
       returnTo = options.returnTo;
       debug('req.oidc.login() called with returnTo: %s', returnTo);
     } else if (req.method === 'GET' && req.originalUrl) {
-      returnTo = req.originalUrl;
+      // Collapse any leading slashes to a single slash to prevent Open Redirects
+      returnTo = req.originalUrl.replace(/^\/+/, '/');
       debug('req.oidc.login() without returnTo, using: %s', returnTo);
     }
 

programming_language: TypeScript
filename: requiresAuth.tests.js
change_type: ModificationType.MODIFY
diff: @@ -354,4 +354,21 @@ describe('requiresAuth', () => {
     assert.equal(response.statusCode, 401);
     sinon.assert.notCalled(checkSpy);
   });
+
+  it('should collapse leading slashes on returnTo', async () => {
+    server = await createServer(auth(defaultConfig));
+    const payloads = ['//google.com', '///google.com', '//google.com'];
+    for (const payload of payloads) {
+      const response = await request({ url: `${baseUrl}${payload}` });
+      const state = new URL(response.headers.location).searchParams.get(
+        'state'
+      );
+      const decoded = Buffer.from(state, 'base64');
+      const parsed = JSON.parse(decoded);
+
+      assert.equal(response.statusCode, 302);
+      assert.include(response.headers.location, 'https://op.example.com');
+      assert.equal(parsed.returnTo, '/google.com');
+    }
+  });
 });

programming_language: TypeScript