VYPR
Moderate severityNVD Advisory· Published Dec 16, 2021· Updated Aug 4, 2024

Open redirect in nextjs-auth0

CVE-2021-43812

Description

The Auth0 Next.js SDK is a library for implementing user authentication in Next.js applications. Versions before 1.6.2 do not filter out certain returnTo parameter values from the login url, which expose the application to an open redirect vulnerability. Users are advised to upgrade as soon as possible. There are no known workarounds for this issue.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
@auth0/nextjs-auth0npm
< 1.6.21.6.2

Affected products

1

Patches

1
0bbd9f8a0c93

Enforce configured host on user supplied returnTo (#557)

https://github.com/auth0/nextjs-auth0Adam McgrathDec 15, 2021via ghsa
6 files changed · +571 33
  • src/handlers/login.ts+10 7 modified
    @@ -1,8 +1,8 @@
     import { NextApiResponse, NextApiRequest } from 'next';
     import { AuthorizationParameters, HandleLogin as BaseHandleLogin } from '../auth0-session';
    -import isSafeRedirect from '../utils/url-helpers';
    +import toSafeRedirect from '../utils/url-helpers';
     import { assertReqRes } from '../utils/assert';
    -import { NextConfig } from '../config';
    +import { BaseConfig, NextConfig } from '../config';
     import { HandlerError } from '../utils/errors';
     
     /**
    @@ -117,16 +117,19 @@ export type HandleLogin = (req: NextApiRequest, res: NextApiResponse, options?:
     /**
      * @ignore
      */
    -export default function handleLoginFactory(handler: BaseHandleLogin, nextConfig: NextConfig): HandleLogin {
    +export default function handleLoginFactory(
    +  handler: BaseHandleLogin,
    +  nextConfig: NextConfig,
    +  baseConfig: BaseConfig
    +): HandleLogin {
       return async (req, res, options = {}): Promise<void> => {
         try {
           assertReqRes(req, res);
           if (req.query.returnTo) {
    -        const returnTo = Array.isArray(req.query.returnTo) ? req.query.returnTo[0] : req.query.returnTo;
    +        const dangerousReturnTo = Array.isArray(req.query.returnTo) ? req.query.returnTo[0] : req.query.returnTo;
    +        const safeBaseUrl = new URL(options.authorizationParams?.redirect_uri || baseConfig.baseURL);
     
    -        if (!isSafeRedirect(returnTo)) {
    -          throw new Error('Invalid value provided for returnTo, must be a relative url');
    -        }
    +        const returnTo = toSafeRedirect(dangerousReturnTo, safeBaseUrl);
     
             options = { ...options, returnTo };
           }
    
  • src/index.ts+1 1 modified
    @@ -77,7 +77,7 @@ export const initAuth0: InitAuth0 = (params) => {
       const getAccessToken = accessTokenFactory(nextConfig, getClient, sessionCache);
       const withApiAuthRequired = withApiAuthRequiredFactory(sessionCache);
       const withPageAuthRequired = withPageAuthRequiredFactory(nextConfig.routes.login, getSession);
    -  const handleLogin = loginHandler(baseHandleLogin, nextConfig);
    +  const handleLogin = loginHandler(baseHandleLogin, nextConfig, baseConfig);
       const handleLogout = logoutHandler(baseHandleLogout);
       const handleCallback = callbackHandler(baseHandleCallback, nextConfig);
       const handleProfile = profileHandler(getClient, getAccessToken, sessionCache);
    
  • src/utils/url-helpers.ts+11 10 modified
    @@ -1,16 +1,17 @@
     /**
      * Helper which tests if a URL can safely be redirected to. Requires the URL to be relative.
    - * @param url
    + * @param dangerousRedirect
    + * @param safeBaseUrl
      */
    -export default function isSafeRedirect(url: string): boolean {
    -  if (typeof url !== 'string') {
    -    throw new TypeError(`Invalid url: ${url}`);
    +export default function toSafeRedirect(dangerousRedirect: string, safeBaseUrl: URL): string | undefined {
    +  let url: URL;
    +  try {
    +    url = new URL(dangerousRedirect, safeBaseUrl);
    +  } catch (e) {
    +    return undefined;
       }
    -
    -  // Prevent open redirects using the //foo.com format (double forward slash).
    -  if (/\/\//.test(url)) {
    -    return false;
    +  if (url.origin === safeBaseUrl.origin) {
    +    return url.toString();
       }
    -
    -  return !/^[a-zA-Z][a-zA-Z\d+\-.]*:/.test(url);
    +  return undefined;
     }
    
  • tests/fixtures/open-redirect-payloads.json+487 0 added
    @@ -0,0 +1,487 @@
    +[
    +  "javascript:alert(1)",
    +  "java%0d%0ascript%0d%0a:alert(0)",
    +  "javascript://%250Aalert(1)",
    +  "javascript://%250Aalert(1)//?1",
    +  "javascript://%250A1?alert(1):0",
    +  "%09Jav%09ascript:alert(document.domain)",
    +  "javascript://%250Alert(document.location=document.cookie)",
    +  "/%09/javascript:alert(1);",
    +  "/%09/javascript:alert(1)",
    +  "//%5cjavascript:alert(1);",
    +  "//%5cjavascript:alert(1)",
    +  "/%5cjavascript:alert(1);",
    +  "/%5cjavascript:alert(1)",
    +  "javascript://%0aalert(1)",
    +  "<>javascript:alert(1);",
    +  "//javascript:alert(1);",
    +  "//javascript:alert(1)",
    +  "/javascript:alert(1);",
    +  "/javascript:alert(1)",
    +  "javascript:alert(1)",
    +  "javascript:alert(1);",
    +  "javascript:alert(1)",
    +  "javascripT://anything%0D%0A%0D%0Awindow.alert(document.cookie)",
    +  "javascript:confirm(1)",
    +  "javascript://https://whitelisted.com/?z=%0Aalert(1)",
    +  "javascript:prompt(1)",
    +  "jaVAscript://whitelisted.com//%0d%0aalert(1);//",
    +  "javascript://whitelisted.com?%a0alert%281%29",
    +  "/x:1/:///%01javascript:alert(document.cookie)/",
    +  "<>//Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ",
    +  "//;@Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ",
    +  "/////Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ/",
    +  "/////Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ",
    +  "////Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ//",
    +  "////Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ/",
    +  "///;@Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ",
    +  "///Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ//",
    +  "///Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ/",
    +  "///Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ",
    +  "///Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ/",
    +  "//Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ//",
    +  "//Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ/",
    +  "//Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ",
    +  "/.Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ",
    +  "//Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ/",
    +  "/〱Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ",
    +  ".Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ",
    +  "@Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ",
    +  "//Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ/",
    +  "〱Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ",
    +  "//Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ%00。Pⓦ",
    +  "%01https://Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ",
    +  "%01https://google.com",
    +  "////%09/Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ",
    +  "///%09/Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ",
    +  "//%09/Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ",
    +  "/%09/Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ",
    +  "////%09/google.com",
    +  "///%09/google.com",
    +  "//%09/google.com",
    +  "/%09/google.com",
    +  "////%09/whitelisted.com@Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ",
    +  "///%09/whitelisted.com@Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ",
    +  "//%09/whitelisted.com@Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ",
    +  "/%09/whitelisted.com@Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ",
    +  "////%09/whitelisted.com@google.com",
    +  "///%09/whitelisted.com@google.com",
    +  "//%09/whitelisted.com@google.com",
    +  "/%09/whitelisted.com@google.com",
    +  "&%0d%0a1Location:https://google.com",
    +  "%19Jav%09asc%09ript:https%20://whitelisted.com/%250Aconfirm%25281%2529",
    +  "////216.58.214.206",
    +  "///216.58.214.206",
    +  "//216.58.214.206",
    +  "/\\216.58.214.206",
    +  "/216.58.214.206",
    +  "216.58.214.206",
    +  "////Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ/%2e%2e",
    +  "///Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ/%2e%2e",
    +  "////Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ/%2e%2e%2f",
    +  "///Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ/%2e%2e%2f",
    +  "//Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ/%2e%2e%2f",
    +  "////Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ/%2f..",
    +  "///Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ/%2f..",
    +  "//Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ/%2f..",
    +  "%2f216.58.214.206//",
    +  "%2f216.58.214.206",
    +  "%2f216.58.214.206%2f%2f",
    +  "////Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ/%2f%2e%2e",
    +  "///Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ/%2f%2e%2e",
    +  "//Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ/%2f%2e%2e",
    +  "/Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ/%2f%2e%2e",
    +  "//%2f%2fⓁ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ",
    +  "/%2f%2fⓁ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ",
    +  "%2f$2f216.58.214.206",
    +  "$2f%2f216.58.214.206%2f%2f",
    +  "%2f$2f3627734734",
    +  "$2f%2f3627734734%2f%2f",
    +  "//%2f%2fgoogle.com",
    +  "/%2f%2fgoogle.com",
    +  "$2f%2fgoogle.com",
    +  "%2f$2fgoogle.com",
    +  "$2f%2fgoogle.com%2f%2f",
    +  "%2f3627734734//",
    +  "%2f3627734734",
    +  "%2f3627734734%2f%2f",
    +  "/%2f%5c%2f%67%6f%6f%67%6c%65%2e%63%6f%6d/",
    +  "/%2f%5c%2f%6c%6f%63%61%6c%64%6f%6d%61%69%6e%2e%70%77/",
    +  "%2fgoogle.com//",
    +  "%2fgoogle.com",
    +  "%2fgoogle.com%2f%2f",
    +  "////3627734734",
    +  "///3627734734",
    +  "//3627734734",
    +  "/3627734734",
    +  "3627734734",
    +  "//3H6k7lIAiqjfNeN@whitelisted.com@Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ/",
    +  "//3H6k7lIAiqjfNeN@whitelisted.com+@Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ/",
    +  "//3H6k7lIAiqjfNeN@whitelisted.com@google.com/",
    +  "//3H6k7lIAiqjfNeN@whitelisted.com+@google.com/",
    +  "////%5cⓁ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ",
    +  "///%5cⓁ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ",
    +  "//%5cⓁ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ",
    +  "/%5cⓁ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ",
    +  "////%5cgoogle.com",
    +  "///%5cgoogle.com",
    +  "//%5cgoogle.com",
    +  "/%5cgoogle.com",
    +  "////%5cwhitelisted.com@Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ",
    +  "///%5cwhitelisted.com@Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ",
    +  "//%5cwhitelisted.com@Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ",
    +  "/%5cwhitelisted.com@Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ",
    +  "////%5cwhitelisted.com@google.com",
    +  "///%5cwhitelisted.com@google.com",
    +  "//%5cwhitelisted.com@google.com",
    +  "/%5cwhitelisted.com@google.com",
    +  "/%68%74%74%70%3a%2f%2f%67%6f%6f%67%6c%65%2e%63%6f%6d",
    +  "%68%74%74%70%3a%2f%2f%67%6f%6f%67%6c%65%2e%63%6f%6d",
    +  "%68%74%74%70%73%3a%2f%2f%6c%6f%63%61%6c%64%6f%6d%61%69%6e%2e%70%77",
    +  "//Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ:80?@whitelisted.com/",
    +  "//Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ:80#@whitelisted.com/",
    +  "\";alert(0);//",
    +  "data:text/html;base64,PHNjcmlwdD5hbGVydCgiSGVsbG8iKTs8L3NjcmlwdD4=",
    +  "data:text/html;base64,PHNjcmlwdD5hbGVydCgiWFNTIik7PC9zY3JpcHQ+Cg==",
    +  "data:text/html;base64,PHNjcmlwdD5hbGVydCgiWFNTIik8L3NjcmlwdD4=",
    +  "data:whitelisted.com;text/html;charset=UTF-8,<html><script>document.write(document.domain);</script><iframe/src=xxxxx>aaaa</iframe></html>",
    +  "//Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ%E3%80%82pw",
    +  "//google%00.com",
    +  "/google%252ecom",
    +  "google%252ecom",
    +  "<>//google.com",
    +  "/<>//google.com",
    +  "//;@google.com",
    +  "///;@google.com",
    +  "/////google.com/",
    +  "/////google.com",
    +  "////;@google.com",
    +  "////google.com//",
    +  "////google.com/",
    +  "////google.com",
    +  "///;@google.com",
    +  "///google.com//",
    +  "///google.com/",
    +  "///google.com",
    +  "///google.com/",
    +  "//google.com",
    +  "//google.com//",
    +  "//google.com/",
    +  "//google.com",
    +  "/.google.com",
    +  "///google.com/",
    +  "//google.com/",
    +  "//google.com",
    +  "/google.com",
    +  "/〱google.com",
    +  "/google.com",
    +  "../google.com",
    +  ".google.com",
    +  "@google.com",
    +  "//google.com/",
    +  "〱google.com",
    +  "google.com",
    +  "google.com%23@whitelisted.com",
    +  "////google.com/%2e%2e",
    +  "///google.com/%2e%2e",
    +  "//google.com/%2e%2e",
    +  "/google.com/%2e%2e",
    +  "//google.com/%2E%2E",
    +  "////google.com/%2e%2e%2f",
    +  "///google.com/%2e%2e%2f",
    +  "//google.com/%2e%2e%2f",
    +  "////google.com/%2f..",
    +  "///google.com/%2f..",
    +  "//google.com/%2f..",
    +  "//google.com/%2F..",
    +  "/google.com/%2F..",
    +  "////google.com/%2f%2e%2e",
    +  "///google.com/%2f%2e%2e",
    +  "//google.com/%2f%2e%2e",
    +  "/google.com/%2f%2e%2e",
    +  "//google.com//%2F%2E%2E",
    +  "//google.com:80?@whitelisted.com/",
    +  "//google.com:80#@whitelisted.com/",
    +  "google.com/.jpg",
    +  "//google.com\twhitelisted.com/",
    +  "//google.com/whitelisted.com",
    +  "//google.com@whitelisted.com",
    +  "google.com/whitelisted.com",
    +  "//google%E3%80%82com",
    +  "/http://Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ",
    +  "/http:/Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ",
    +  "http://;@Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ",
    +  "http://.Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ",
    +  "http:/Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ",
    +  "http:Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ",
    +  "http://00330.00072.0000326.00000316",
    +  "http:00330.00072.0000326.00000316",
    +  "http://00330.0x3a.54990",
    +  "http:00330.0x3a.54990",
    +  "http://00330.3856078",
    +  "http:00330.3856078",
    +  "http://0330.072.0326.0316",
    +  "http:0330.072.0326.0316",
    +  "http:%0a%0dⓁ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ",
    +  "http:%0a%0dgoogle.com",
    +  "http://0xd8.072.54990",
    +  "http:0xd8.072.54990",
    +  "http://0xd8.0x3a.0xd6.0xce",
    +  "http:0xd8.0x3a.0xd6.0xce",
    +  "http://0xd8.3856078",
    +  "http:0xd8.3856078",
    +  "http://0xd83ad6ce",
    +  "http:0xd83ad6ce",
    +  "http://[::216.58.214.206]",
    +  "http:[::216.58.214.206]",
    +  "http://Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ%23.whitelisted.com/",
    +  "http://Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ%2f%2f.whitelisted.com/",
    +  "http://3627734734",
    +  "http:3627734734",
    +  "http://Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ%3F.whitelisted.com/",
    +  "http://3H6k7lIAiqjfNeN@00330.00072.0000326.00000316",
    +  "http:3H6k7lIAiqjfNeN@00330.00072.0000326.00000316",
    +  "http://3H6k7lIAiqjfNeN@00330.0x3a.54990",
    +  "http:3H6k7lIAiqjfNeN@00330.0x3a.54990",
    +  "http://3H6k7lIAiqjfNeN@00330.3856078",
    +  "http:3H6k7lIAiqjfNeN@00330.3856078",
    +  "http://3H6k7lIAiqjfNeN@0330.072.0326.0316",
    +  "http:3H6k7lIAiqjfNeN@0330.072.0326.0316",
    +  "http://3H6k7lIAiqjfNeN@0xd8.072.54990",
    +  "http:3H6k7lIAiqjfNeN@0xd8.072.54990",
    +  "http://3H6k7lIAiqjfNeN@0xd8.0x3a.0xd6.0xce",
    +  "http:3H6k7lIAiqjfNeN@0xd8.0x3a.0xd6.0xce",
    +  "http://3H6k7lIAiqjfNeN@0xd8.3856078",
    +  "http:3H6k7lIAiqjfNeN@0xd8.3856078",
    +  "http://3H6k7lIAiqjfNeN@0xd83ad6ce",
    +  "http:3H6k7lIAiqjfNeN@0xd83ad6ce",
    +  "http://3H6k7lIAiqjfNeN@[::216.58.214.206]",
    +  "http:3H6k7lIAiqjfNeN@[::216.58.214.206]",
    +  "http://3H6k7lIAiqjfNeN@3627734734",
    +  "http:3H6k7lIAiqjfNeN@3627734734",
    +  "http://3H6k7lIAiqjfNeN@472.314.470.462",
    +  "http:3H6k7lIAiqjfNeN@472.314.470.462",
    +  "http://3H6k7lIAiqjfNeN@[::ffff:216.58.214.206]",
    +  "http:3H6k7lIAiqjfNeN@[::ffff:216.58.214.206]",
    +  "http://3H6k7lIAiqjfNeN@whitelisted.com@Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ/",
    +  "http://3H6k7lIAiqjfNeN@whitelisted.com+@Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ/",
    +  "http://3H6k7lIAiqjfNeN@whitelisted.com@google.com/",
    +  "http://3H6k7lIAiqjfNeN@whitelisted.com+@google.com/",
    +  "http://472.314.470.462",
    +  "http:472.314.470.462",
    +  "http://Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ%5c%5c.whitelisted.com/",
    +  "/http://%67%6f%6f%67%6c%65%2e%63%6f%6d",
    +  "http://%67%6f%6f%67%6c%65%2e%63%6f%6d",
    +  "http://Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ:80?@whitelisted.com/",
    +  "http://Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ:80#@whitelisted.com/",
    +  "http://[::ffff:216.58.214.206]",
    +  "http:[::ffff:216.58.214.206]",
    +  "/http://google.com",
    +  "/http:/google.com",
    +  "http://;@google.com",
    +  "http://.google.com",
    +  "http://google.com",
    +  "http://google.com",
    +  "http:/google.com",
    +  "http:google.com",
    +  "http://google.com%23.whitelisted.com/",
    +  "http://google.com%2f%2f.whitelisted.com/",
    +  "http://google.com%3F.whitelisted.com/",
    +  "http://google.com%5c%5c.whitelisted.com/",
    +  "http://google.com:80?@whitelisted.com/",
    +  "http://google.com:80#@whitelisted.com/",
    +  "http://google.com\twhitelisted.com/",
    +  "//https://Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ//",
    +  "/https://Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ/",
    +  "https://Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ//",
    +  "https://Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ/",
    +  "https://Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ",
    +  "https:Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ",
    +  "https://%09/Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ",
    +  "/https://%09/google.com",
    +  "https://%09/google.com",
    +  "https://%09/whitelisted.com@Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ",
    +  "https://%09/whitelisted.com@google.com",
    +  "https://%0a%0dⓁ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ",
    +  "https://%0a%0dgoogle.com",
    +  "//https:///Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ/%2e%2e",
    +  "/https://Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ/%2e%2e",
    +  "https:///Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ/%2e%2e",
    +  "//https://Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ/%2e%2e%2f",
    +  "https://Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ/%2e%2e%2f",
    +  "/https://Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ/%2f..",
    +  "https://Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ/%2f..",
    +  "/https:///Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ/%2f%2e%2e",
    +  "/https://Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ/%2f%2e%2e",
    +  "https:///Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ/%2f%2e%2e",
    +  "https://Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ/%2f%2e%2e",
    +  "https%3a%2f%2fgoogle.com%2f",
    +  "/https://%5cⓁ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ",
    +  "/https:/%5cⓁ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ/",
    +  "https://%5cⓁ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ",
    +  "https:/%5cⓁ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ/",
    +  "/https://%5cgoogle.com",
    +  "/https:/%5cgoogle.com/",
    +  "https://%5cgoogle.com",
    +  "https:/%5cgoogle.com/",
    +  "/https://%5cwhitelisted.com@Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ",
    +  "https://%5cwhitelisted.com@Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ",
    +  "/https://%5cwhitelisted.com@google.com",
    +  "https://%5cwhitelisted.com@google.com",
    +  "https://%6c%6f%63%61%6c%64%6f%6d%61%69%6e%2e%70%77",
    +  "//https://google.com//",
    +  "/https://google.com//",
    +  "/https://google.com/",
    +  "/https://google.com",
    +  "/https:google.com",
    +  "https://////google.com",
    +  "https://google.com//",
    +  "https://google.com/",
    +  "https://google.com",
    +  "https:/google.com",
    +  "https:google.com",
    +  "//https:///google.com/%2e%2e",
    +  "/https://google.com/%2e%2e",
    +  "https:///google.com/%2e%2e",
    +  "//https://google.com/%2e%2e%2f",
    +  "https://google.com/%2e%2e%2f",
    +  "/https://google.com/%2f..",
    +  "https://google.com/%2f..",
    +  "/https:///google.com/%2f%2e%2e",
    +  "/https://google.com/%2f%2e%2e",
    +  "https:///google.com/%2f%2e%2e",
    +  "https://google.com/%2f%2e%2e",
    +  "https://:@google.com@whitelisted.com",
    +  "https://google.com?whitelisted.com",
    +  "https://google.com/whitelisted.com",
    +  "https://google.comwhitelisted.com",
    +  "https://google.com#whitelisted.com",
    +  "https://google%E3%80%82com",
    +  "//https://whitelisted.com@Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ//",
    +  "/https://whitelisted.com@Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ/",
    +  "https://:@Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ@whitelisted.com",
    +  "https://Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ/whitelisted.com",
    +  "https://whitelisted.com;@Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ",
    +  "https://whitelisted.com@Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ//",
    +  "https://whitelisted.com@Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ/",
    +  "https://whitelisted.com@Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ",
    +  "/https://whitelisted.com@Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ/%2e%2e",
    +  "https:///whitelisted.com@Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ/%2e%2e",
    +  "//https://whitelisted.com@Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ/%2e%2e%2f",
    +  "https://whitelisted.com@Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ/%2e%2e%2f",
    +  "/https://whitelisted.com@Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ/%2f..",
    +  "https://whitelisted.com@Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ/%2f..",
    +  "/https:///whitelisted.com@Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ/%2f%2e%2e",
    +  "/https://whitelisted.com@Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ/%2f%2e%2e",
    +  "https:///whitelisted.com@Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ/%2f%2e%2e",
    +  "https://whitelisted.com@Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ/%2f%2e%2e",
    +  "//https://whitelisted.com@google.com//",
    +  "/https://whitelisted.com@google.com/",
    +  "https://whitelisted.com;@google.com",
    +  "https://whitelisted.com.google.com",
    +  "https://whitelisted.com@google.com//",
    +  "https://whitelisted.com@google.com/",
    +  "https://whitelisted.com@google.com",
    +  "/https://whitelisted.com@google.com/%2e%2e",
    +  "https:///whitelisted.com@google.com/%2e%2e",
    +  "//https://whitelisted.com@google.com/%2e%2e%2f",
    +  "https://whitelisted.com@google.com/%2e%2e%2f",
    +  "/https://whitelisted.com@google.com/%2f..",
    +  "https://whitelisted.com@google.com/%2f..",
    +  "/https:///whitelisted.com@google.com/%2f%2e%2e",
    +  "/https://whitelisted.com@google.com/%2f%2e%2e",
    +  "https:///whitelisted.com@google.com/%2f%2e%2e",
    +  "https://whitelisted.com@google.com/%2f%2e%2e",
    +  "/https://whitelisted.com@google.com/%2f.//whitelisted.com@google.com/%2f..",
    +  "https://whitelisted.com/https://Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ/",
    +  "https://whitelisted.com/https://google.com/",
    +  "@https://www.google.com",
    +  "http://Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ\twhitelisted.com/",
    +  "http://whitelisted.com@00330.00072.0000326.00000316",
    +  "http:whitelisted.com@00330.00072.0000326.00000316",
    +  "http://whitelisted.com@00330.0x3a.54990",
    +  "http:whitelisted.com@00330.0x3a.54990",
    +  "http://whitelisted.com@00330.3856078",
    +  "http:whitelisted.com@00330.3856078",
    +  "http://whitelisted.com@0330.072.0326.0316",
    +  "http:whitelisted.com@0330.072.0326.0316",
    +  "http://whitelisted.com@0xd8.072.54990",
    +  "http:whitelisted.com@0xd8.072.54990",
    +  "http://whitelisted.com@0xd8.0x3a.0xd6.0xce",
    +  "http:whitelisted.com@0xd8.0x3a.0xd6.0xce",
    +  "http://whitelisted.com@0xd8.3856078",
    +  "http:whitelisted.com@0xd8.3856078",
    +  "http://whitelisted.com@0xd83ad6ce",
    +  "http:whitelisted.com@0xd83ad6ce",
    +  "http://whitelisted.com@[::216.58.214.206]",
    +  "http:whitelisted.com@[::216.58.214.206]",
    +  "http://whitelisted.com%2eⓁ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ/",
    +  "http://whitelisted.com%2egoogle.com/",
    +  "http://whitelisted.com@3627734734",
    +  "http:whitelisted.com@3627734734",
    +  "http://whitelisted.com@472.314.470.462",
    +  "http:whitelisted.com@472.314.470.462",
    +  "http://whitelisted.com:80%40Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ/",
    +  "http://whitelisted.com:80%40google.com/",
    +  "http://whitelisted.com@[::ffff:216.58.214.206]",
    +  "http:whitelisted.com@[::ffff:216.58.214.206]",
    +  "http://whitelisted.com@google.com/",
    +  "http://whitelisted.com+&@google.com#+@whitelisted.com/",
    +  "http://whitelisted.com+&@Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ#+@whitelisted.com/",
    +  "http://www.google.com.whitelisted.com",
    +  "http://www.Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ.whitelisted.com",
    +  "ja\nva\tscript\r:alert(1)",
    +  "java%09script:alert(1)",
    +  "java%0ascript:alert(1)",
    +  "java%0d%0ascript%0d%0a:alert(0)",
    +  "java%0dscript:alert(1)",
    +  "Javas%26%2399;ript:alert(1)",
    +  "//Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ\twhitelisted.com/",
    +  "\u006A\u0061\u0076\u0061\u0073\u0063\u0072\u0069\u0070\u0074\u003aalert(1)",
    +  "////whitelisted.com@Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ//",
    +  "////whitelisted.com@Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ/",
    +  "///whitelisted.com@Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ//",
    +  "///whitelisted.com@Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ/",
    +  "//Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ/whitelisted.com",
    +  "//Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ@whitelisted.com",
    +  "//whitelisted.com@Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ//",
    +  "//whitelisted.com@Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ/",
    +  "Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ/whitelisted.com",
    +  "whitelisted.com;@Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ",
    +  "////whitelisted.com@Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ/%2e%2e",
    +  "///whitelisted.com@Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ/%2e%2e",
    +  "////whitelisted.com@Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ/%2e%2e%2f",
    +  "///whitelisted.com@Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ/%2e%2e%2f",
    +  "//whitelisted.com@Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ/%2e%2e%2f",
    +  "////whitelisted.com@Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ/%2f..",
    +  "///whitelisted.com@Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ/%2f..",
    +  "//whitelisted.com@Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ/%2f..",
    +  "////whitelisted.com@Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ/%2f%2e%2e",
    +  "///whitelisted.com@Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ/%2f%2e%2e",
    +  "//whitelisted.com@Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ/%2f%2e%2e",
    +  "/whitelisted.com:80%40google.com",
    +  "whitelisted.com@%E2%80%AE@google.com",
    +  "////whitelisted.com@google.com//",
    +  "////whitelisted.com@google.com/",
    +  "///whitelisted.com@google.com//",
    +  "///whitelisted.com@google.com/",
    +  "//whitelisted.com@google.com//",
    +  "//whitelisted.com@google.com/",
    +  "whitelisted.com;@google.com",
    +  "whitelisted.com.google.com",
    +  "////whitelisted.com@google.com/%2e%2e",
    +  "///whitelisted.com@google.com/%2e%2e",
    +  "////whitelisted.com@google.com/%2e%2e%2f",
    +  "///whitelisted.com@google.com/%2e%2e%2f",
    +  "//whitelisted.com@google.com/%2e%2e%2f",
    +  "////whitelisted.com@google.com/%2f..",
    +  "///whitelisted.com@google.com/%2f..",
    +  "//whitelisted.com@google.com/%2f..",
    +  "////whitelisted.com@google.com/%2f%2e%2e",
    +  "///whitelisted.com@google.com/%2f%2e%2e",
    +  "//whitelisted.com@google.com/%2f%2e%2e",
    +  "//whitelisted.com+&@google.com#+@whitelisted.com/",
    +  "//whitelisted.com@https:///Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ/%2e%2e",
    +  "//whitelisted.com@https:///google.com/%2e%2e",
    +  "//whitelisted.com+&@Ⓛ𝐨𝗰�𝕝ⅆ𝓸ⓜₐℹⓃ。Pⓦ#+@whitelisted.com/"
    +]
    
  • tests/handlers/login.test.ts+43 5 modified
    @@ -214,7 +214,7 @@ describe('login handler', () => {
     
         const decodedState = decodeState(state.split('.')[0]);
         expect(decodedState).toEqual({
    -      returnTo: '/foo'
    +      returnTo: new URL('/foo', withoutApi.baseURL).toString()
         });
       });
     
    @@ -229,7 +229,7 @@ describe('login handler', () => {
     
         const decodedState = decodeState(state.split('.')[0]);
         expect(decodedState).toEqual({
    -      returnTo: '/foo'
    +      returnTo: new URL('/foo', withoutApi.baseURL).toString()
         });
       });
     
    @@ -239,9 +239,47 @@ describe('login handler', () => {
         };
         const baseUrl = await setup(withoutApi, { loginOptions });
     
    -    await expect(
    -      get(baseUrl, '/api/auth/login?returnTo=https://www.google.com', { fullResponse: true })
    -    ).rejects.toThrow('Invalid value provided for returnTo, must be a relative url');
    +    const cookieJar = new CookieJar();
    +    await get(baseUrl, '/api/auth/login?returnTo=https://www.google.com', { cookieJar });
    +    const { value: state } = getCookie('state', cookieJar, baseUrl) as Cookie;
    +
    +    const decodedState = decodeState(state.split('.')[0]);
    +    expect(decodedState).toEqual({});
    +  });
    +
    +  test('should allow absolute urls in params of returnTo urls', async () => {
    +    const loginOptions = {
    +      returnTo: '/default-redirect'
    +    };
    +    const baseUrl = await setup(withoutApi, { loginOptions });
    +
    +    const cookieJar = new CookieJar();
    +    await get(baseUrl, '/api/auth/login?returnTo=/foo?url=https://www.google.com', { cookieJar });
    +    const { value: state } = getCookie('state', cookieJar, baseUrl) as Cookie;
    +
    +    const decodedState = decodeState(state.split('.')[0]);
    +    expect(decodedState).toEqual({
    +      returnTo: new URL('/foo?url=https://www.google.com', withoutApi.baseURL).toString()
    +    });
    +  });
    +
    +  test('should redirect relative to the redirect_uri over the base url', async () => {
    +    const loginOptions = {
    +      returnTo: '/default-redirect',
    +      authorizationParams: {
    +        redirect_uri: 'https://other-org.acme.com/api/auth/callback'
    +      }
    +    };
    +    const baseUrl = await setup(withoutApi, { loginOptions });
    +
    +    const cookieJar = new CookieJar();
    +    await get(baseUrl, '/api/auth/login?returnTo=/foo', { cookieJar });
    +    const { value: state } = getCookie('state', cookieJar, baseUrl) as Cookie;
    +
    +    const decodedState = decodeState(state.split('.')[0]);
    +    expect(decodedState).toEqual({
    +      returnTo: 'https://other-org.acme.com/foo'
    +    });
       });
     
       test('should escape html in errors', async () => {
    
  • tests/utils/url-helpers.test.ts+19 10 modified
    @@ -1,25 +1,34 @@
    -import isSafeRedirect from '../../src/utils/url-helpers';
    +import toSafeRedirect from '../../src/utils/url-helpers';
    +import payloads from '../fixtures/open-redirect-payloads.json';
     
     describe('url-helpers', () => {
    +  const safeBaseUrl = new URL('http://www.example.com');
    +
       describe('isSafeRedirect', () => {
         test('should not allow absolute urls', () => {
    -      expect(isSafeRedirect('file://foo')).toEqual(false);
    -      expect(isSafeRedirect('https://foo')).toEqual(false);
    -      expect(isSafeRedirect('http://foo')).toEqual(false);
    +      expect(toSafeRedirect('file://foo', safeBaseUrl)).toEqual(undefined);
    +      expect(toSafeRedirect('https://foo', safeBaseUrl)).toEqual(undefined);
    +      expect(toSafeRedirect('http://foo', safeBaseUrl)).toEqual(undefined);
         });
     
         test('should allow relative urls', () => {
    -      expect(isSafeRedirect('/foo')).toEqual(true);
    -      expect(isSafeRedirect('/foo?some=value')).toEqual(true);
    +      expect(toSafeRedirect('/foo', safeBaseUrl)).toEqual('http://www.example.com/foo');
    +      expect(toSafeRedirect('foo', safeBaseUrl)).toEqual('http://www.example.com/foo');
    +      expect(toSafeRedirect('/foo?some=value', safeBaseUrl)).toEqual('http://www.example.com/foo?some=value');
    +      expect(toSafeRedirect('/foo?someUrl=https://www.google.com', safeBaseUrl)).toEqual(
    +        'http://www.example.com/foo?someUrl=https://www.google.com'
    +      );
    +      expect(toSafeRedirect('/foo', new URL('http://www.example.com:8888'))).toEqual('http://www.example.com:8888/foo');
         });
     
         test('should prevent open redirects', () => {
    -      expect(isSafeRedirect('//google.com')).toEqual(false);
    -      expect(isSafeRedirect('///google.com')).toEqual(false);
    +      for (const payload of payloads) {
    +        expect(toSafeRedirect(payload, safeBaseUrl) || safeBaseUrl.toString()).toMatch(/^http:\/\/www.example.com\//);
    +      }
         });
     
    -    test('should throw when non string provided', () => {
    -      expect(isSafeRedirect.bind(null)).toThrow('Invalid url: undefined');
    +    test('should not throw for empty redirect', () => {
    +      expect(toSafeRedirect.bind(null, '', safeBaseUrl)).not.toThrow();
         });
       });
     });
    

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

4

News mentions

0

No linked articles in our index yet.