This affects the package snyk-broker before 4.73.0. It allows arbitrary file reads for users with access to Snyk's internal network via directory traversal.

module.exports = ruleSource => {
  let rules = [];
  const config = require('../config');

  // polymorphic support
  if (Array.isArray(ruleSource)) {
    rules = ruleSource;
  } else if (ruleSource) {
    try {
      rules = require(ruleSource);
    } catch (error) {
      logger.warn({ ruleSource, error }, 'Unable to parse rule source, ignoring');
    }
  }

  if (!Array.isArray(rules)) {
    throw new Error(`Expected array of filter rules, got '${typeof rules}' instead.`);
  }

  logger.info({ rulesCount: rules.length }, 'loading new rules');

  // array of entries with
  const tests = rules.map(entry => {
    const keys = [];
    let { method, origin, path, valid, stream } = entry;
    method = (method || 'get').toLowerCase();
    valid = valid || [];

    const bodyFilters = valid.filter(v => !!v.path && !v.regex);
    const bodyRegexFilters = valid.filter(v => !!v.path && !!v.regex);
    const queryFilters = valid.filter(v => !!v.queryParam);

    // now track if there's any values that we need to interpolate later
    const fromConfig = {};

    // slightly bespoke version of replace-vars.js
    path = (path || '').replace(/(\${.*?})/g, (_, match) => {
      const key = match.slice(2, -1); // ditch the wrappers
      fromConfig[key] = config[key] || '';
      return ':' + key;
    });

    origin = replace(origin, config);

    if (path[0] !== '/') {
      path = '/' + path;
    }

    logger.info({ method, path }, 'adding new filter rule');
    const regexp = pathRegexp(path, keys);

    return (req) => {
      // check the request method
      if (req.method.toLowerCase() !== method && method !== 'any') {
        return false;
      }

      // Discard any fragments before further processing
      const mainURI = req.url.split('#')[0];

      // query params might contain additional "?"s, only split on the 1st one
      const parts = mainURI.split('?');
      let [url, querystring] = [parts[0], parts.slice(1).join('?')];
      const res = regexp.exec(url);
      if (!res) {
        // no url match
        return false;
      }

      // reconstruct the url from the user config
      for (let i = 1; i < res.length; i++) {
        const val = fromConfig[keys[i - 1].name];
        if (val) {
          url = url.replace(res[i], val);
        }
      }

      // if validity filters are present, at least one must be satisfied
      if (bodyFilters.length || bodyRegexFilters.length ||
          queryFilters.length) {
        let isValid;

        let parsedBody;
        if (bodyFilters.length) {
          parsedBody = tryJSONParse(req.body);

          // validate against the body
          isValid = bodyFilters.some(({ path, value }) => {
            return undefsafe(parsedBody, path, value);
          });
        }

        if (!isValid && bodyRegexFilters.length) {
          parsedBody = parsedBody || tryJSONParse(req.body);

          // validate against the body by regex
          isValid = bodyRegexFilters.some(({ path, regex }) => {
            try {
              const re = new RegExp(regex);
              return re.test(undefsafe(parsedBody, path));
            } catch (error) {
              logger.error({error, path, regex},
                'failed to test regex rule');
              return false;
            }
          });
        }

        // no need to check query filters if the request is already valid
        if (!isValid && queryFilters.length) {
          const parsedQuerystring = qs.parse(querystring);

          // validate against the querystring
          isValid = queryFilters.some(({ queryParam, values }) => {
            return values.some(value =>
              minimatch(parsedQuerystring[queryParam] || '', value)
            );
          });
        }

        if (!isValid) {
          return false;
        }
      }

      logger.debug({ path, origin, url, querystring }, 'rule matched');

      querystring = (querystring) ? `?${querystring}` : '';
      return {
        url: origin + url + querystring,
        auth: entry.auth && authHeader(entry.auth),
        stream
      };
    };
  });

  return (payload, callback) => {
    let res = false;
    logger.debug({ rulesCount: tests.length }, 'looking for a rule match');

    for (const test of tests) {
      res = test(payload);
      if (res) {
        break;
      }
    }
    if (!res) {
      return callback(Error('blocked'));
    }

    return callback(null, res);
  };
};

module.exports = ruleSource => {
  let rules = [];
  const config = require('../config');

  // polymorphic support
  if (Array.isArray(ruleSource)) {
    rules = ruleSource;
  } else if (ruleSource) {
    try {
      rules = require(ruleSource);
    } catch (error) {
      logger.warn({ ruleSource, error }, 'Unable to parse rule source, ignoring');
    }
  }

  if (!Array.isArray(rules)) {
    throw new Error(`Expected array of filter rules, got '${typeof rules}' instead.`);
  }

  logger.info({ rulesCount: rules.length }, 'loading new rules');

  // array of entries with
  const tests = rules.map(entry => {
    const keys = [];
    let { method, origin, path: entryPath, valid, stream } = entry;
    method = (method || 'get').toLowerCase();
    valid = valid || [];

    const bodyFilters = valid.filter(v => !!v.path && !v.regex);
    const bodyRegexFilters = valid.filter(v => !!v.path && !!v.regex);
    const queryFilters = valid.filter(v => !!v.queryParam);

    // now track if there's any values that we need to interpolate later
    const fromConfig = {};

    // slightly bespoke version of replace-vars.js
    entryPath = (entryPath || '').replace(/(\${.*?})/g, (_, match) => {
      const key = match.slice(2, -1); // ditch the wrappers
      fromConfig[key] = config[key] || '';
      return ':' + key;
    });

    origin = replace(origin, config);

    if (entryPath[0] !== '/') {
      entryPath = '/' + entryPath;
    }

    logger.info({ method, path: entryPath }, 'adding new filter rule');
    const regexp = pathRegexp(entryPath, keys);

    return (req) => {
      // check the request method
      if (req.method.toLowerCase() !== method && method !== 'any') {
        return false;
      }

      // Do not allow directory traversal
      if (path.normalize(req.url) !== req.url) {
        return false;
      }

      // Discard any fragments before further processing
      const mainURI = req.url.split('#')[0];

      // query params might contain additional "?"s, only split on the 1st one
      const parts = mainURI.split('?');
      let [url, querystring] = [parts[0], parts.slice(1).join('?')];
      const res = regexp.exec(url);
      if (!res) {
        // no url match
        return false;
      }

      // reconstruct the url from the user config
      for (let i = 1; i < res.length; i++) {
        const val = fromConfig[keys[i - 1].name];
        if (val) {
          url = url.replace(res[i], val);
        }
      }

      // if validity filters are present, at least one must be satisfied
      if (bodyFilters.length || bodyRegexFilters.length ||
          queryFilters.length) {
        let isValid;

        let parsedBody;
        if (bodyFilters.length) {
          parsedBody = tryJSONParse(req.body);

          // validate against the body
          isValid = bodyFilters.some(({ path, value }) => {
            return undefsafe(parsedBody, path, value);
          });
        }

        if (!isValid && bodyRegexFilters.length) {
          parsedBody = parsedBody || tryJSONParse(req.body);

          // validate against the body by regex
          isValid = bodyRegexFilters.some(({ path, regex }) => {
            try {
              const re = new RegExp(regex);
              return re.test(undefsafe(parsedBody, path));
            } catch (error) {
              logger.error({error, path, regex},
                'failed to test regex rule');
              return false;
            }
          });
        }

        // no need to check query filters if the request is already valid
        if (!isValid && queryFilters.length) {
          const parsedQuerystring = qs.parse(querystring);

          // validate against the querystring
          isValid = queryFilters.some(({ queryParam, values }) => {
            return values.some(value =>
              minimatch(parsedQuerystring[queryParam] || '', value)
            );
          });
        }

        if (!isValid) {
          return false;
        }
      }

      logger.debug({ path: entryPath, origin, url, querystring }, 'rule matched');

      querystring = (querystring) ? `?${querystring}` : '';
      return {
        url: origin + url + querystring,
        auth: entry.auth && authHeader(entry.auth),
        stream
      };
    };
  });

  return (payload, callback) => {
    let res = false;
    logger.debug({ rulesCount: tests.length }, 'looking for a rule match');

    for (const test of tests) {
      res = test(payload);
      if (res) {
        break;
      }
    }
    if (!res) {
      return callback(Error('blocked'));
    }

    return callback(null, res);
  };
};

--- a/lib/filters/index.js
+++ b/lib/filters/index.js
@@ -22,7 +22,7 @@
   // array of entries with
   const tests = rules.map(entry => {
     const keys = [];
-    let { method, origin, path, valid, stream } = entry;
+    let { method, origin, path: entryPath, valid, stream } = entry;
     method = (method || 'get').toLowerCase();
     valid = valid || [];

@@ -34,7 +34,7 @@
     const fromConfig = {};

     // slightly bespoke version of replace-vars.js
-    path = (path || '').replace(/(\${.*?})/g, (_, match) => {
+    entryPath = (entryPath || '').replace(/(\${.*?})/g, (_, match) => {
       const key = match.slice(2, -1); // ditch the wrappers
       fromConfig[key] = config[key] || '';
       return ':' + key;
@@ -42,16 +42,21 @@

     origin = replace(origin, config);

-    if (path[0] !== '/') {
-      path = '/' + path;
+    if (entryPath[0] !== '/') {
+      entryPath = '/' + entryPath;
     }

-    logger.info({ method, path }, 'adding new filter rule');
-    const regexp = pathRegexp(path, keys);
+    logger.info({ method, path: entryPath }, 'adding new filter rule');
+    const regexp = pathRegexp(entryPath, keys);

     return (req) => {
       // check the request method
       if (req.method.toLowerCase() !== method && method !== 'any') {
+        return false;
+      }
+
+      // Do not allow directory traversal
+      if (path.normalize(req.url) !== req.url) {
         return false;
       }

@@ -123,7 +128,7 @@
         }
       }

-      logger.debug({ path, origin, url, querystring }, 'rule matched');
+      logger.debug({ path: entryPath, origin, url, querystring }, 'rule matched');

       querystring = (querystring) ? `?${querystring}` : '';
       return {

#!/bin/bash
# From ghcr.io/anonymous2578-data/cve-2020-7649:latest
# bash /workspace/fix-run.sh
set -e

cd /workspace/broker
git apply --whitespace=nowarn /workspace/test.patch /workspace/fix.patch
node test/unit/filters.test.js


A vulnerability was found in pastebinit up to 0.2.2 and classified as problematic. Affected by this issue is the function pasteHandler of the file server.go. The manipulation of the argument r.URL.Path leads to path traversal. Upgrading to version 0.2.3 is able to address this issue. The name of the patch is 1af2facb6d95976c532b7f8f82747d454a092272. It is recommended to upgrade the affected component. The identifier of this vulnerability is VDB-217040.

External Control of File Name or Path

The product allows user input to control or influence paths or file names that are used in filesystem operations.

Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')

The product uses external input to construct a pathname that is intended to identify a file or directory that is located underneath a restricted parent directory, but the product does not properly neutralize special elements within the pathname that can cause the pathname to resolve to a location that is outside of the restricted directory.

func (cmd *serverCommand) pasteHandler(w http.ResponseWriter, r *http.Request) {
	if r.URL.Path == "/" {
		// they want the root, make them auth
		u, p, ok := r.BasicAuth()
		if (u != username || p != password) || !ok {
			w.Header().Set("WWW-Authenticate", `Basic realm="`+baseuri+`"`)
			w.WriteHeader(401)
			w.Write([]byte("401 Unauthorized\n"))
			return
		}

		html, err := cmd.generateIndexHTML()
		if err != nil {
			writeError(w, fmt.Sprintf("generating index html failed: %v", err))
			return
		}

		// write the html
		w.Header().Set("Content-Type", "text/html")
		fmt.Fprint(w, html)
		logrus.Info("index file rendered")
		return
	}

	filename := filepath.Join(cmd.storage, strings.Trim(r.URL.Path, "/"))

	var handler func(data []byte) (string, error)

	if strings.HasSuffix(filename, "/raw") {
		// if they want the raw file serve a text/plain Content-Type
		w.Header().Set("Content-Type", "text/plain")
		// trim '/raw' from the filename so we can get the right file
		filename = strings.TrimSuffix(filename, "/raw")
		handler = func(data []byte) (string, error) {
			return string(data), nil
		}
	} else if strings.HasSuffix(filename, "/html") {
		// check if they want html
		w.Header().Set("Content-Type", "text/html")
		filename = strings.TrimSuffix(filename, "/html")
		handler = func(data []byte) (string, error) {
			return string(data), nil
		}
	} else if strings.HasSuffix(filename, "/ansi") {
		// check if they want ansi colored text
		w.Header().Set("Content-Type", "text/html")
		filename = strings.TrimSuffix(filename, "/ansi")
		// try to syntax highlight the file
		handler = func(data []byte) (string, error) {
			return fmt.Sprintf("%s
%s
%s", htmlBegin, terminal.Render(data), htmlEnd), nil
		}
	} else {
		// check if they want html
		w.Header().Set("Content-Type", "text/html")
		handler = func(data []byte) (string, error) {
			highlighted, err := syntaxhighlight.AsHTML(data)
			if err != nil {
				return "", err
			}
			return fmt.Sprintf("%s
%s
%s", htmlBegin, string(highlighted), htmlEnd), nil
		}
	}

	// check if the file exists
	if _, err := os.Stat(filename); os.IsNotExist(err) {
		writeError(w, fmt.Sprintf("No such file or directory: %s", filename))
		return
	}

	// read the file
	src, err := ioutil.ReadFile(filename)
	if err != nil {
		writeError(w, fmt.Sprintf("Reading file %s failed: %v", filename, err))
		return
	}

	data, err := handler(src)
	if err != nil {
		writeError(w, fmt.Sprintf("Processing file %s failed: %v", filename, err))
	}

	io.WriteString(w, data)
	return
}

func (cmd *serverCommand) pasteHandler(w http.ResponseWriter, r *http.Request) {
	if r.URL.Path == "/" {
		// they want the root, make them auth
		u, p, ok := r.BasicAuth()
		if (u != username || p != password) || !ok {
			w.Header().Set("WWW-Authenticate", `Basic realm="`+baseuri+`"`)
			w.WriteHeader(401)
			w.Write([]byte("401 Unauthorized\n"))
			return
		}

		html, err := cmd.generateIndexHTML()
		if err != nil {
			writeError(w, fmt.Sprintf("generating index html failed: %v", err))
			return
		}

		// write the html
		w.Header().Set("Content-Type", "text/html")
		fmt.Fprint(w, html)
		logrus.Info("index file rendered")
		return
	}

	filename := filepath.Join(cmd.storage, filepath.FromSlash(path.Clean("/"+strings.Trim(r.URL.Path, "/"))))

	var handler func(data []byte) (string, error)

	if strings.HasSuffix(filename, "/raw") {
		// if they want the raw file serve a text/plain Content-Type
		w.Header().Set("Content-Type", "text/plain")
		// trim '/raw' from the filename so we can get the right file
		filename = strings.TrimSuffix(filename, "/raw")
		handler = func(data []byte) (string, error) {
			return string(data), nil
		}
	} else if strings.HasSuffix(filename, "/html") {
		// check if they want html
		w.Header().Set("Content-Type", "text/html")
		filename = strings.TrimSuffix(filename, "/html")
		handler = func(data []byte) (string, error) {
			return string(data), nil
		}
	} else if strings.HasSuffix(filename, "/ansi") {
		// check if they want ansi colored text
		w.Header().Set("Content-Type", "text/html")
		filename = strings.TrimSuffix(filename, "/ansi")
		// try to syntax highlight the file
		handler = func(data []byte) (string, error) {
			return fmt.Sprintf("%s
%s
%s", htmlBegin, terminal.Render(data), htmlEnd), nil
		}
	} else {
		// check if they want html
		w.Header().Set("Content-Type", "text/html")
		handler = func(data []byte) (string, error) {
			highlighted, err := syntaxhighlight.AsHTML(data)
			if err != nil {
				return "", err
			}
			return fmt.Sprintf("%s
%s
%s", htmlBegin, string(highlighted), htmlEnd), nil
		}
	}

	// check if the file exists
	if _, err := os.Stat(filename); os.IsNotExist(err) {
		writeError(w, fmt.Sprintf("No such file or directory: %s", r.URL.Path))
		return
	}

	// read the file
	src, err := ioutil.ReadFile(filename)
	if err != nil {
		writeError(w, fmt.Sprintf("Reading file %s failed: %v", filename, err))
		return
	}

	data, err := handler(src)
	if err != nil {
		writeError(w, fmt.Sprintf("Processing file %s failed: %v", filename, err))
	}

	io.WriteString(w, data)
	return
}

--- a/server.go
+++ b/server.go
@@ -22,7 +22,7 @@
 		return
 	}

-	filename := filepath.Join(cmd.storage, strings.Trim(r.URL.Path, "/"))
+	filename := filepath.Join(cmd.storage, filepath.FromSlash(path.Clean("/"+strings.Trim(r.URL.Path, "/"))))

 	var handler func(data []byte) (string, error)

@@ -63,7 +63,7 @@

 	// check if the file exists
 	if _, err := os.Stat(filename); os.IsNotExist(err) {
-		writeError(w, fmt.Sprintf("No such file or directory: %s", filename))
+		writeError(w, fmt.Sprintf("No such file or directory: %s", r.URL.Path))
 		return
 	}


@fastify/passport is a port of passport authentication library for the Fastify ecosystem. Applications using `@fastify/passport` in affected versions for user authentication, in combination with `@fastify/session` as the underlying session management mechanism, are vulnerable to session fixation attacks from network and same-site attackers. fastify applications rely on the `@fastify/passport` library for user authentication. The login and user validation are performed by the `authenticate` function. When executing this function, the `sessionId` is preserved between the pre-login and the authenticated session. Network and same-site attackers can hijack the victim's session by tossing a valid `sessionId` cookie in the victim's browser and waiting for the victim to log in on the website. As a solution, newer versions of `@fastify/passport` regenerate `sessionId` upon login, preventing the attacker-controlled pre-session cookie from being upgraded to an authenticated session. Users are advised to upgrade. There are no known workarounds for this vulnerability.

Session Fixation

Authenticating a user, or otherwise establishing a new user session, without invalidating any existing session identifier gives an attacker the opportunity to steal authenticated sessions.

  async logIn(request: FastifyRequest, user: any) {
    const object = await this.serializeUser(user, request)
    request.session.set(this.key, object)
  }

  async logOut(request: FastifyRequest) {
    request.session.set(this.key, undefined)
  }

  async logIn(request: FastifyRequest, user: any) {
    const object = await this.serializeUser(user, request)
    // Handle sessions using @fastify/session
    if (request.session.regenerate) {
      // regenerate session to guard against session fixation
      await request.session.regenerate()
    }
    request.session.set(this.key, object)
  }

  async logOut(request: FastifyRequest) {
    request.session.set(this.key, undefined)
    if (request.session.regenerate) {
      await request.session.regenerate()
    }
  }

--- a/src/session-managers/SecureSessionManager.ts
+++ b/src/session-managers/SecureSessionManager.ts
@@ -1,4 +1,9 @@
   async logIn(request: FastifyRequest, user: any) {
     const object = await this.serializeUser(user, request)
+    // Handle sessions using @fastify/session
+    if (request.session.regenerate) {
+      // regenerate session to guard against session fixation
+      await request.session.regenerate()
+    }
     request.session.set(this.key, object)
   }

--- a/src/session-managers/SecureSessionManager.ts
+++ b/src/session-managers/SecureSessionManager.ts
@@ -1,3 +1,6 @@
   async logOut(request: FastifyRequest) {
     request.session.set(this.key, undefined)
+    if (request.session.regenerate) {
+      await request.session.regenerate()
+    }
   }


Arbitrary code execution is possible in reduce-css-calc node module <=1.2.4 through crafted css. This makes cross sites scripting (XSS) possible on the client and arbitrary code injection possible on the server and user input is passed to the `calc` function.

Improper Control of Generation of Code ('Code Injection')

The product constructs all or part of a code segment using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the syntax or behavior of the intended code segment.

  function evaluateExpression (expression, functionIdentifier, call) {
    if (stack++ > MAX_STACK) {
      stack = 0
      throw new Error("Call stack overflow for " + call)
    }

    if (expression === "") {
      throw new Error(functionIdentifier + "(): '" + call + "' must contain a non-whitespace string")
    }

    expression = evaluateNestedExpression(expression, call)

    var units = getUnitsInExpression(expression)

    // If the expression contains multiple units or CSS variables,
    // then let the expression be (i.e. browser calc())
    if (units.length > 1 || expression.indexOf("var(") > -1) {
      return functionIdentifier + "(" + expression + ")"
    }

    var unit = units[0] || ""

    if (unit === "%") {
      // Convert percentages to numbers, to handle expressions like: 50% * 50% (will become: 25%):
      // console.log(expression)
      expression = expression.replace(/\b[0-9\.]+%/g, function(percent) {
        return parseFloat(percent.slice(0, -1)) * 0.01
      })
    }

    // Remove units in expression:
    var toEvaluate = expression.replace(new RegExp(unit, "gi"), "")
    var result

    try {
      result = eval(toEvaluate)
    }
    catch (e) {
      return functionIdentifier + "(" + expression + ")"
    }

    // Transform back to a percentage result:
    if (unit === "%") {
      result *= 100
    }

    // adjust rounding shit
    // (0.1 * 0.2 === 0.020000000000000004)
    if (functionIdentifier.length || unit === "%") {
      result = Math.round(result * decimalPrecision) / decimalPrecision
    }

    // Add unit
    result += unit

    return result
  }

  function evaluateExpression (expression, functionIdentifier, call) {
    if (stack++ > MAX_STACK) {
      stack = 0
      throw new Error("Call stack overflow for " + call)
    }

    if (expression === "") {
      throw new Error(functionIdentifier + "(): '" + call + "' must contain a non-whitespace string")
    }

    expression = evaluateNestedExpression(expression, call)

    var units = getUnitsInExpression(expression)

    // If the expression contains multiple units or CSS variables,
    // then let the expression be (i.e. browser calc())
    if (units.length > 1 || expression.indexOf("var(") > -1) {
      return functionIdentifier + "(" + expression + ")"
    }

    var unit = units[0] || ""

    if (unit === "%") {
      // Convert percentages to numbers, to handle expressions like: 50% * 50% (will become: 25%):
      // console.log(expression)
      expression = expression.replace(/\b[0-9\.]+%/g, function(percent) {
        return parseFloat(percent.slice(0, -1)) * 0.01
      })
    }

    // Remove units in expression:
    var toEvaluate = expression.replace(new RegExp(unit, "gi"), "")
    var result

    try {
      result = mexp.eval(toEvaluate)
    }
    catch (e) {
      return functionIdentifier + "(" + expression + ")"
    }

    // Transform back to a percentage result:
    if (unit === "%") {
      result *= 100
    }

    // adjust rounding shit
    // (0.1 * 0.2 === 0.020000000000000004)
    if (functionIdentifier.length || unit === "%") {
      result = Math.round(result * decimalPrecision) / decimalPrecision
    }

    // Add unit
    result += unit

    return result
  }

  // CSS allow to omit 0 for 0.* values,
  // but math-expression-evaluator does not
  value = value.replace(/\s(\.[0-9])/g, " 0$1")

--- a/index.js
+++ b/index.js
@@ -33,7 +33,7 @@
     var result

     try {
-      result = eval(toEvaluate)
+      result = mexp.eval(toEvaluate)
     }
     catch (e) {
       return functionIdentifier + "(" + expression + ")"

--- /dev/null
+++ b/index.js
@@ -0,0 +1,3 @@
+  // CSS allow to omit 0 for 0.* values,
+  // but math-expression-evaluator does not
+  value = value.replace(/\s(\.[0-9])/g, " 0$1")

#!/bin/bash
# From ghcr.io/anonymous2578-data/cve-2016-10548:latest
# bash /workspace/fix-run.sh
set -e

cd /workspace/reduce-css-calc
git apply --whitespace=nowarn /workspace/test.patch /workspace/fix.patch
jest --forceExit ./poc

#!/bin/bash
# From ghcr.io/anonymous2578-data/cve-2016-10548:latest
# bash /workspace/unit_test.sh
set -e

cd /workspace/reduce-css-calc
git apply --whitespace=nowarn /workspace/fix.patch
npm test


BuildKit is a toolkit for converting source code to build artifacts in an efficient, expressive and repeatable manner. A malicious BuildKit frontend or Dockerfile using RUN --mount could trick the feature that removes empty files created for the mountpoints into removing a file outside the container, from the host system. The issue has been fixed in v0.12.5. Workarounds include avoiding using BuildKit frontends from an untrusted source or building an untrusted Dockerfile containing RUN --mount feature.

func MountStubsCleaner(ctx context.Context, dir string, mounts []Mount, recursive bool) func() {
	names := []string{"/etc/resolv.conf", "/etc/hosts"}

	for _, m := range mounts {
		names = append(names, m.Dest)
	}

	paths := make([]string, 0, len(names))

	for _, p := range names {
		p = filepath.Join("/", p)
		if p == "/" {
			continue
		}
		realPath, err := fs.RootPath(dir, p)
		if err != nil {
			continue
		}

		for {
			_, err = os.Lstat(realPath)
			if !(errors.Is(err, os.ErrNotExist) || errors.Is(err, syscall.ENOTDIR)) {
				break
			}
			paths = append(paths, realPath)

			if !recursive {
				break
			}

			realPathNext := filepath.Dir(realPath)
			if realPath == realPathNext {
				break
			}
			realPath = realPathNext
		}
	}

	return func() {
		for _, p := range paths {
			st, err := os.Lstat(p)
			if err != nil {
				continue
			}
			if st.IsDir() {
				entries, err := os.ReadDir(p)
				if err != nil {
					continue
				}
				if len(entries) != 0 {
					continue
				}
			} else if st.Size() != 0 {
				continue
			}

			// Back up the timestamps of the dir for reproducible builds
			// https://github.com/moby/buildkit/issues/3148
			dir := filepath.Dir(p)
			dirSt, err := os.Stat(dir)
			if err != nil {
				bklog.G(ctx).WithError(err).Warnf("Failed to stat %q (parent of mount stub %q)", dir, p)
				continue
			}
			mtime := dirSt.ModTime()
			atime, err := system.Atime(dirSt)
			if err != nil {
				bklog.G(ctx).WithError(err).Warnf("Failed to stat atime of %q (parent of mount stub %q)", dir, p)
				atime = mtime
			}

			if err := os.Remove(p); err != nil {
				bklog.G(ctx).WithError(err).Warnf("Failed to remove mount stub %q", p)
			}

			// Restore the timestamps of the dir
			if err := os.Chtimes(dir, atime, mtime); err != nil {
				bklog.G(ctx).WithError(err).Warnf("Failed to restore time time mount stub timestamp (os.Chtimes(%q, %v, %v))", dir, atime, mtime)
			}
		}
	}
}

func MountStubsCleaner(ctx context.Context, dir string, mounts []Mount, recursive bool) func() {
	names := []string{"/etc/resolv.conf", "/etc/hosts"}

	for _, m := range mounts {
		names = append(names, m.Dest)
	}

	paths := make([]string, 0, len(names))

	for _, p := range names {
		p = filepath.Join("/", p)
		if p == "/" {
			continue
		}
		realPath, err := fs.RootPath(dir, p)
		if err != nil {
			continue
		}

		for {
			_, err = os.Lstat(realPath)
			if !(errors.Is(err, os.ErrNotExist) || errors.Is(err, syscall.ENOTDIR)) {
				break
			}
			paths = append(paths, realPath)

			if !recursive {
				break
			}

			realPathNext := filepath.Dir(realPath)
			if realPath == realPathNext || realPathNext == dir {
				break
			}
			realPath = realPathNext
		}
	}

	return func() {
		for _, p := range paths {
			p, err := fs.RootPath(dir, strings.TrimPrefix(p, dir))
			if err != nil {
				continue
			}

			st, err := os.Lstat(p)
			if err != nil {
				continue
			}
			if st.IsDir() {
				entries, err := os.ReadDir(p)
				if err != nil {
					continue
				}
				if len(entries) != 0 {
					continue
				}
			} else if st.Size() != 0 {
				continue
			}

			// Back up the timestamps of the dir for reproducible builds
			// https://github.com/moby/buildkit/issues/3148
			parent := filepath.Dir(p)
			if realPath, err := fs.RootPath(dir, strings.TrimPrefix(parent, dir)); err != nil || realPath != parent {
				continue
			}

			dirSt, err := os.Stat(parent)
			if err != nil {
				bklog.G(ctx).WithError(err).Warnf("Failed to stat %q (parent of mount stub %q)", dir, p)
				continue
			}
			mtime := dirSt.ModTime()
			atime, err := system.Atime(dirSt)
			if err != nil {
				bklog.G(ctx).WithError(err).Warnf("Failed to stat atime of %q (parent of mount stub %q)", dir, p)
				atime = mtime
			}

			if err := os.Remove(p); err != nil {
				bklog.G(ctx).WithError(err).Warnf("Failed to remove mount stub %q", p)
			}

			// Restore the timestamps of the dir
			if err := os.Chtimes(parent, atime, mtime); err != nil {
				bklog.G(ctx).WithError(err).Warnf("Failed to restore time time mount stub timestamp (os.Chtimes(%q, %v, %v))", dir, atime, mtime)
			}
		}
	}
}

--- a/executor/stubs.go
+++ b/executor/stubs.go
@@ -29,7 +29,7 @@
 			}

 			realPathNext := filepath.Dir(realPath)
-			if realPath == realPathNext {
+			if realPath == realPathNext || realPathNext == dir {
 				break
 			}
 			realPath = realPathNext
@@ -38,6 +38,11 @@

 	return func() {
 		for _, p := range paths {
+			p, err := fs.RootPath(dir, strings.TrimPrefix(p, dir))
+			if err != nil {
+				continue
+			}
+
 			st, err := os.Lstat(p)
 			if err != nil {
 				continue
@@ -56,8 +61,12 @@

 			// Back up the timestamps of the dir for reproducible builds
 			// https://github.com/moby/buildkit/issues/3148
-			dir := filepath.Dir(p)
-			dirSt, err := os.Stat(dir)
+			parent := filepath.Dir(p)
+			if realPath, err := fs.RootPath(dir, strings.TrimPrefix(parent, dir)); err != nil || realPath != parent {
+				continue
+			}
+
+			dirSt, err := os.Stat(parent)
 			if err != nil {
 				bklog.G(ctx).WithError(err).Warnf("Failed to stat %q (parent of mount stub %q)", dir, p)
 				continue
@@ -74,7 +83,7 @@
 			}

 			// Restore the timestamps of the dir
-			if err := os.Chtimes(dir, atime, mtime); err != nil {
+			if err := os.Chtimes(parent, atime, mtime); err != nil {
 				bklog.G(ctx).WithError(err).Warnf("Failed to restore time time mount stub timestamp (os.Chtimes(%q, %v, %v))", dir, atime, mtime)
 			}
 		}


The package koa-remove-trailing-slashes before 2.0.2 are vulnerable to Open Redirect via the use of trailing double slashes in the URL when accessing the vulnerable endpoint (such as https://example.com//attacker.example/). The vulnerable code is in index.js::removeTrailingSlashes(), as the web server uses relative URLs instead of absolute URLs.

URL Redirection to Untrusted Site ('Open Redirect')

The web application accepts a user-controlled input that specifies a link to an external site, and uses that link in a redirect.

function removeTrailingSlashes(opts) {
    opts = opts || {};

    if (opts.defer !== false) {
        opts.defer = opts.defer || true;
    }

    if (opts.chained !== false) {
        opts.chained = opts.chained || true;
    }

    return async function(ctx, next) {
        if (opts.defer) {
            await next();
        }

        let path;
        let querystring = '';

        // We have already done a redirect and we will continue if we are in chained mode
        if (opts.chained && ctx.status === 301) {
            const location = ctx.response.get('Location') || '';

            // We can't use ctx.querystring because it may not be up to date
            const parsedLocation = location.match(/\?(.*)$/);
            if (parsedLocation && parsedLocation[1]) {
                querystring = parsedLocation[1];
            }

            path = getPath(location, querystring);
        } else if (ctx.status !== 301) {
            querystring = ctx.querystring;
            path = getPath(ctx.originalUrl, ctx.querystring);
        }

        if (path && haveSlash(path)) {
            path = path.slice(0, -1);
            const query = querystring.length ? '?' + querystring : '';

            ctx.status = 301;
            ctx.redirect(path + query);
        }

        if (!opts.defer) {
            await next();
        }
    };
}

function removeTrailingSlashes(opts) {
    opts = opts || {};

    if (opts.defer !== false) {
        opts.defer = opts.defer || true;
    }

    if (opts.chained !== false) {
        opts.chained = opts.chained || true;
    }

    return async function(ctx, next) {
        if (opts.defer) {
            await next();
        }

        let path;
        let querystring = '';

        // We have already done a redirect and we will continue if we are in chained mode
        if (opts.chained && ctx.status === 301) {
            const location = ctx.response.get('Location') || '';

            // We can't use ctx.querystring because it may not be up to date
            const parsedLocation = location.match(/\?(.*)$/);
            if (parsedLocation && parsedLocation[1]) {
                querystring = parsedLocation[1];
            }

            path = getPath(location, querystring);
        } else if (ctx.status !== 301) {
            querystring = ctx.querystring;
            path = getPath(ctx.originalUrl, ctx.querystring);
        }

        if (path && haveSlash(path)) {
            path = path.slice(0, -1);
            const query = querystring.length ? '?' + querystring : '';

            const newURL = new URL(path + query, ctx.request.URL);

            if (ctx.origin === newURL.origin) {
                ctx.status = 301;
                ctx.redirect(path + query);
            }
        }

        if (!opts.defer) {
            await next();
        }
    };
}

--- a/index.js
+++ b/index.js
@@ -37,8 +37,12 @@
             path = path.slice(0, -1);
             const query = querystring.length ? '?' + querystring : '';

-            ctx.status = 301;
-            ctx.redirect(path + query);
+            const newURL = new URL(path + query, ctx.request.URL);
+
+            if (ctx.origin === newURL.origin) {
+                ctx.status = 301;
+                ctx.redirect(path + query);
+            }
         }

         if (!opts.defer) {

#!/bin/bash
# From ghcr.io/anonymous2578-data/cve-2021-23384:latest
# bash /workspace/fix-run.sh
set -e

cd /workspace/koa-remove-trailing-slashes
git apply --whitespace=nowarn /workspace/test.patch /workspace/fix.patch
npm test

#!/bin/bash
# From ghcr.io/anonymous2578-data/cve-2021-23384:latest
# bash /workspace/unit_test.sh
set -e

cd /workspace/koa-remove-trailing-slashes
git apply --whitespace=nowarn /workspace/fix.patch
npx mocha --grep "should work in a normal scenarion|should not redirect on url that already have been modified|should not redirect on url that is the root|should not redirect on url and url has no trailing slash|should not redirect on url with query and path has no trailing slash"


Jupyter Core is a package for the core common functionality of Jupyter projects. Jupyter Core prior to version 4.11.2 contains an arbitrary code execution vulnerability in `jupyter_core` that stems from `jupyter_core` executing untrusted files in CWD. This vulnerability allows one user to run code as another. Version 4.11.2 contains a patch for this issue. There are no known workarounds.

Improper Authorization

The product does not perform or incorrectly performs an authorization check when an actor attempts to access a resource or perform an action.

Execution with Unnecessary Privileges

The product performs an operation at a privilege level that is higher than the minimum level required, which creates new weaknesses or amplifies the consequences of other weaknesses.

Improper Privilege Management

The product does not properly assign, modify, track, or check privileges for an actor, creating an unintended sphere of control for that actor.

    def config_file_paths(self):
        path = jupyter_config_path()
        if self.config_dir not in path:
            path.insert(0, self.config_dir)
        path.insert(0, os.getcwd())
        return path

    def config_file_paths(self):
        path = jupyter_config_path()
        if self.config_dir not in path:
            # Insert config dir as first item.
            path.insert(0, self.config_dir)
        return path

--- a/jupyter_core/application.py
+++ b/jupyter_core/application.py
@@ -1,6 +1,6 @@
     def config_file_paths(self):
         path = jupyter_config_path()
         if self.config_dir not in path:
+            # Insert config dir as first item.
             path.insert(0, self.config_dir)
-        path.insert(0, os.getcwd())
         return path

#!/bin/bash
# From ghcr.io/anonymous2578-data/cve-2022-39286:latest
# bash /workspace/fix-run.sh
set -e

cd /workspace/jupyter_core
git apply --whitespace=nowarn /workspace/test.patch /workspace/fix.patch
/workspace/PoC_env/CVE-2022-39286/bin/python -m pytest jupyter_core/tests/test_application.py::test_load_config jupyter_core/tests/test_application.py::test_load_config_no_cwd jupyter_core/tests/test_application.py::test_load_bad_config -p no:warning --disable-warnings

#!/bin/bash
# From ghcr.io/anonymous2578-data/cve-2022-39286:latest
# bash /workspace/unit_test.sh
set -e

cd /workspace/jupyter_core
git apply --whitespace=nowarn /workspace/fix.patch
/workspace/PoC_env/CVE-2022-39286/bin/python -m pytest jupyter_core/tests/test_application.py -k "not test_load_config" -p no:warning --disable-warnings


Incorrect Session Validation in Apache Airflow Webserver versions prior to 1.10.14 with default config allows a malicious airflow user on site A where they log in normally, to access unauthorized Airflow Webserver on Site B through the session from Site A. This does not affect users who have changed the default value for `[webserver] secret_key` config.

def create_app(config=None, session=None, testing=False, app_name="Airflow"):
    global app, appbuilder
    app = Flask(__name__)
    if conf.getboolean('webserver', 'ENABLE_PROXY_FIX'):
        app.wsgi_app = ProxyFix(
            app.wsgi_app,
            num_proxies=conf.get("webserver", "PROXY_FIX_NUM_PROXIES", fallback=None),
            x_for=conf.getint("webserver", "PROXY_FIX_X_FOR", fallback=1),
            x_proto=conf.getint("webserver", "PROXY_FIX_X_PROTO", fallback=1),
            x_host=conf.getint("webserver", "PROXY_FIX_X_HOST", fallback=1),
            x_port=conf.getint("webserver", "PROXY_FIX_X_PORT", fallback=1),
            x_prefix=conf.getint("webserver", "PROXY_FIX_X_PREFIX", fallback=1)
        )
    app.secret_key = conf.get('webserver', 'SECRET_KEY')
    app.config['PERMANENT_SESSION_LIFETIME'] = timedelta(minutes=settings.get_session_lifetime_config())

    app.config.from_pyfile(settings.WEBSERVER_CONFIG, silent=True)
    app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
    app.config['APP_NAME'] = app_name
    app.config['TESTING'] = testing

    app.config['SESSION_COOKIE_HTTPONLY'] = True
    app.config['SESSION_COOKIE_SECURE'] = conf.getboolean('webserver', 'COOKIE_SECURE')
    app.config['SESSION_COOKIE_SAMESITE'] = conf.get('webserver', 'COOKIE_SAMESITE')

    if config:
        app.config.from_mapping(config)

    if 'SQLALCHEMY_ENGINE_OPTIONS' not in app.config:
        app.config['SQLALCHEMY_ENGINE_OPTIONS'] = settings.prepare_engine_args()

    csrf.init_app(app)

    db = SQLA(app)

    from airflow import api
    api.load_auth()
    api.API_AUTH.api_auth.init_app(app)

    # flake8: noqa: F841
    cache = Cache(app=app, config={'CACHE_TYPE': 'filesystem', 'CACHE_DIR': '/tmp'})

    from airflow.www_rbac.blueprints import routes
    app.register_blueprint(routes)

    configure_logging()
    configure_manifest_files(app)

    with app.app_context():
        from airflow.www_rbac.security import AirflowSecurityManager
        security_manager_class = app.config.get('SECURITY_MANAGER_CLASS') or \
            AirflowSecurityManager

        if not issubclass(security_manager_class, AirflowSecurityManager):
            raise Exception(
                """Your CUSTOM_SECURITY_MANAGER must now extend AirflowSecurityManager,
                 not FAB's security manager.""")

        appbuilder = AppBuilder(
            app,
            db.session if not session else session,
            security_manager_class=security_manager_class,
            base_template='airflow/master.html',
            update_perms=conf.getboolean('webserver', 'UPDATE_FAB_PERMS'))

        def init_views(appbuilder):
            from airflow.www_rbac import views
            # Remove the session from scoped_session registry to avoid
            # reusing a session with a disconnected connection
            appbuilder.session.remove()
            appbuilder.add_view_no_menu(views.Airflow())
            appbuilder.add_view_no_menu(views.DagModelView())
            appbuilder.add_view(views.DagRunModelView,
                                "DAG Runs",
                                category="Browse",
                                category_icon="fa-globe")
            appbuilder.add_view(views.JobModelView,
                                "Jobs",
                                category="Browse")
            appbuilder.add_view(views.LogModelView,
                                "Logs",
                                category="Browse")
            appbuilder.add_view(views.SlaMissModelView,
                                "SLA Misses",
                                category="Browse")
            appbuilder.add_view(views.TaskInstanceModelView,
                                "Task Instances",
                                category="Browse")
            appbuilder.add_view(views.TaskRescheduleModelView,
                                "Task Reschedules",
                                category="Browse")
            appbuilder.add_view(views.ConfigurationView,
                                "Configurations",
                                category="Admin",
                                category_icon="fa-user")
            appbuilder.add_view(views.ConnectionModelView,
                                "Connections",
                                category="Admin")
            appbuilder.add_view(views.PoolModelView,
                                "Pools",
                                category="Admin")
            appbuilder.add_view(views.VariableModelView,
                                "Variables",
                                category="Admin")
            appbuilder.add_view(views.XComModelView,
                                "XComs",
                                category="Admin")

            if "dev" in version.version:
                airflow_doc_site = "https://airflow.readthedocs.io/en/latest"
            else:
                airflow_doc_site = 'https://airflow.apache.org/docs/{}'.format(version.version)

            appbuilder.add_link("Documentation",
                                href=airflow_doc_site,
                                category="Docs",
                                category_icon="fa-cube")
            appbuilder.add_link("GitHub",
                                href='https://github.com/apache/airflow',
                                category="Docs")
            appbuilder.add_view(views.VersionView,
                                'Version',
                                category='About',
                                category_icon='fa-th')

            def integrate_plugins():
                """Integrate plugins to the context"""
                from airflow.plugins_manager import (
                    flask_appbuilder_views, flask_appbuilder_menu_links
                )

                for v in flask_appbuilder_views:
                    log.debug("Adding view %s", v["name"])
                    appbuilder.add_view(v["view"],
                                        v["name"],
                                        category=v["category"])
                for ml in sorted(flask_appbuilder_menu_links, key=lambda x: x["name"]):
                    log.debug("Adding menu link %s", ml["name"])
                    appbuilder.add_link(ml["name"],
                                        href=ml["href"],
                                        category=ml["category"],
                                        category_icon=ml["category_icon"])

            integrate_plugins()
            # Garbage collect old permissions/views after they have been modified.
            # Otherwise, when the name of a view or menu is changed, the framework
            # will add the new Views and Menus names to the backend, but will not
            # delete the old ones.

        def init_plugin_blueprints(app):
            from airflow.plugins_manager import flask_blueprints

            for bp in flask_blueprints:
                log.debug("Adding blueprint %s:%s", bp["name"], bp["blueprint"].import_name)
                app.register_blueprint(bp["blueprint"])

        init_views(appbuilder)
        init_plugin_blueprints(app)

        if conf.getboolean('webserver', 'UPDATE_FAB_PERMS'):
            security_manager = appbuilder.sm
            security_manager.sync_roles()

        from airflow.www_rbac.api.experimental import endpoints as e
        # required for testing purposes otherwise the module retains
        # a link to the default_auth
        if app.config['TESTING']:
            if six.PY2:
                reload(e) # noqa
            else:
                import importlib
                importlib.reload(e)

        app.register_blueprint(e.api_experimental, url_prefix='/api/experimental')

        server_timezone = conf.get('core', 'default_timezone')
        if server_timezone == "system":
            server_timezone = pendulum.local_timezone().name
        elif server_timezone == "utc":
            server_timezone = "UTC"

        default_ui_timezone = conf.get('webserver', 'default_ui_timezone')
        if default_ui_timezone == "system":
            default_ui_timezone = pendulum.local_timezone().name
        elif default_ui_timezone == "utc":
            default_ui_timezone = "UTC"
        if not default_ui_timezone:
            default_ui_timezone = server_timezone

        @app.context_processor
        def jinja_globals():  # pylint: disable=unused-variable

            globals = {
                'server_timezone': server_timezone,
                'default_ui_timezone': default_ui_timezone,
                'hostname': socket.getfqdn() if conf.getboolean(
                    'webserver', 'EXPOSE_HOSTNAME', fallback=True) else 'redact',
                'navbar_color': conf.get('webserver', 'NAVBAR_COLOR'),
                'log_fetch_delay_sec': conf.getint(
                    'webserver', 'log_fetch_delay_sec', fallback=2),
                'log_auto_tailing_offset': conf.getint(
                    'webserver', 'log_auto_tailing_offset', fallback=30),
                'log_animation_speed': conf.getint(
                    'webserver', 'log_animation_speed', fallback=1000),
                'state_color_mapping': STATE_COLORS
            }

            if 'analytics_tool' in conf.getsection('webserver'):
                globals.update({
                    'analytics_tool': conf.get('webserver', 'ANALYTICS_TOOL'),
                    'analytics_id': conf.get('webserver', 'ANALYTICS_ID')
                })

            return globals

        @app.teardown_appcontext
        def shutdown_session(exception=None):
            settings.Session.remove()

        @app.after_request
        def apply_caching(response):
            _x_frame_enabled = conf.getboolean('webserver', 'X_FRAME_ENABLED', fallback=True)
            if not _x_frame_enabled:
                response.headers["X-Frame-Options"] = "DENY"
            return response

        @app.before_request
        def make_session_permanent():
            flask_session.permanent = True

    return app, appbuilder

def create_app(config=None, session=None, testing=False, app_name="Airflow"):
    global app, appbuilder
    app = Flask(__name__)
    if conf.getboolean('webserver', 'ENABLE_PROXY_FIX'):
        app.wsgi_app = ProxyFix(
            app.wsgi_app,
            num_proxies=conf.get("webserver", "PROXY_FIX_NUM_PROXIES", fallback=None),
            x_for=conf.getint("webserver", "PROXY_FIX_X_FOR", fallback=1),
            x_proto=conf.getint("webserver", "PROXY_FIX_X_PROTO", fallback=1),
            x_host=conf.getint("webserver", "PROXY_FIX_X_HOST", fallback=1),
            x_port=conf.getint("webserver", "PROXY_FIX_X_PORT", fallback=1),
            x_prefix=conf.getint("webserver", "PROXY_FIX_X_PREFIX", fallback=1)
        )
    app.secret_key = conf.get('webserver', 'SECRET_KEY')
    app.config['PERMANENT_SESSION_LIFETIME'] = timedelta(minutes=settings.get_session_lifetime_config())

    if conf.get('webserver', 'SECRET_KEY') == "temporary_key":
        app.secret_key = os.urandom(16)
    else:
        app.secret_key = conf.get('webserver', 'SECRET_KEY')

    app.config.from_pyfile(settings.WEBSERVER_CONFIG, silent=True)
    app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
    app.config['APP_NAME'] = app_name
    app.config['TESTING'] = testing

    app.config['SESSION_COOKIE_HTTPONLY'] = True
    app.config['SESSION_COOKIE_SECURE'] = conf.getboolean('webserver', 'COOKIE_SECURE')
    app.config['SESSION_COOKIE_SAMESITE'] = conf.get('webserver', 'COOKIE_SAMESITE')

    if config:
        app.config.from_mapping(config)

    if 'SQLALCHEMY_ENGINE_OPTIONS' not in app.config:
        app.config['SQLALCHEMY_ENGINE_OPTIONS'] = settings.prepare_engine_args()

    csrf.init_app(app)

    db = SQLA(app)

    from airflow import api
    api.load_auth()
    api.API_AUTH.api_auth.init_app(app)

    # flake8: noqa: F841
    cache = Cache(app=app, config={'CACHE_TYPE': 'filesystem', 'CACHE_DIR': '/tmp'})

    from airflow.www_rbac.blueprints import routes
    app.register_blueprint(routes)

    configure_logging()
    configure_manifest_files(app)

    with app.app_context():
        from airflow.www_rbac.security import AirflowSecurityManager
        security_manager_class = app.config.get('SECURITY_MANAGER_CLASS') or \
            AirflowSecurityManager

        if not issubclass(security_manager_class, AirflowSecurityManager):
            raise Exception(
                """Your CUSTOM_SECURITY_MANAGER must now extend AirflowSecurityManager,
                 not FAB's security manager.""")

        appbuilder = AppBuilder(
            app,
            db.session if not session else session,
            security_manager_class=security_manager_class,
            base_template='airflow/master.html',
            update_perms=conf.getboolean('webserver', 'UPDATE_FAB_PERMS'))

        def init_views(appbuilder):
            from airflow.www_rbac import views
            # Remove the session from scoped_session registry to avoid
            # reusing a session with a disconnected connection
            appbuilder.session.remove()
            appbuilder.add_view_no_menu(views.Airflow())
            appbuilder.add_view_no_menu(views.DagModelView())
            appbuilder.add_view(views.DagRunModelView,
                                "DAG Runs",
                                category="Browse",
                                category_icon="fa-globe")
            appbuilder.add_view(views.JobModelView,
                                "Jobs",
                                category="Browse")
            appbuilder.add_view(views.LogModelView,
                                "Logs",
                                category="Browse")
            appbuilder.add_view(views.SlaMissModelView,
                                "SLA Misses",
                                category="Browse")
            appbuilder.add_view(views.TaskInstanceModelView,
                                "Task Instances",
                                category="Browse")
            appbuilder.add_view(views.TaskRescheduleModelView,
                                "Task Reschedules",
                                category="Browse")
            appbuilder.add_view(views.ConfigurationView,
                                "Configurations",
                                category="Admin",
                                category_icon="fa-user")
            appbuilder.add_view(views.ConnectionModelView,
                                "Connections",
                                category="Admin")
            appbuilder.add_view(views.PoolModelView,
                                "Pools",
                                category="Admin")
            appbuilder.add_view(views.VariableModelView,
                                "Variables",
                                category="Admin")
            appbuilder.add_view(views.XComModelView,
                                "XComs",
                                category="Admin")

            if "dev" in version.version:
                airflow_doc_site = "https://airflow.readthedocs.io/en/latest"
            else:
                airflow_doc_site = 'https://airflow.apache.org/docs/{}'.format(version.version)

            appbuilder.add_link("Documentation",
                                href=airflow_doc_site,
                                category="Docs",
                                category_icon="fa-cube")
            appbuilder.add_link("GitHub",
                                href='https://github.com/apache/airflow',
                                category="Docs")
            appbuilder.add_view(views.VersionView,
                                'Version',
                                category='About',
                                category_icon='fa-th')

            def integrate_plugins():
                """Integrate plugins to the context"""
                from airflow.plugins_manager import (
                    flask_appbuilder_views, flask_appbuilder_menu_links
                )

                for v in flask_appbuilder_views:
                    log.debug("Adding view %s", v["name"])
                    appbuilder.add_view(v["view"],
                                        v["name"],
                                        category=v["category"])
                for ml in sorted(flask_appbuilder_menu_links, key=lambda x: x["name"]):
                    log.debug("Adding menu link %s", ml["name"])
                    appbuilder.add_link(ml["name"],
                                        href=ml["href"],
                                        category=ml["category"],
                                        category_icon=ml["category_icon"])

            integrate_plugins()
            # Garbage collect old permissions/views after they have been modified.
            # Otherwise, when the name of a view or menu is changed, the framework
            # will add the new Views and Menus names to the backend, but will not
            # delete the old ones.

        def init_plugin_blueprints(app):
            from airflow.plugins_manager import flask_blueprints

            for bp in flask_blueprints:
                log.debug("Adding blueprint %s:%s", bp["name"], bp["blueprint"].import_name)
                app.register_blueprint(bp["blueprint"])

        init_views(appbuilder)
        init_plugin_blueprints(app)

        if conf.getboolean('webserver', 'UPDATE_FAB_PERMS'):
            security_manager = appbuilder.sm
            security_manager.sync_roles()

        from airflow.www_rbac.api.experimental import endpoints as e
        # required for testing purposes otherwise the module retains
        # a link to the default_auth
        if app.config['TESTING']:
            if six.PY2:
                reload(e) # noqa
            else:
                import importlib
                importlib.reload(e)

        app.register_blueprint(e.api_experimental, url_prefix='/api/experimental')

        server_timezone = conf.get('core', 'default_timezone')
        if server_timezone == "system":
            server_timezone = pendulum.local_timezone().name
        elif server_timezone == "utc":
            server_timezone = "UTC"

        default_ui_timezone = conf.get('webserver', 'default_ui_timezone')
        if default_ui_timezone == "system":
            default_ui_timezone = pendulum.local_timezone().name
        elif default_ui_timezone == "utc":
            default_ui_timezone = "UTC"
        if not default_ui_timezone:
            default_ui_timezone = server_timezone

        @app.context_processor
        def jinja_globals():  # pylint: disable=unused-variable

            globals = {
                'server_timezone': server_timezone,
                'default_ui_timezone': default_ui_timezone,
                'hostname': socket.getfqdn() if conf.getboolean(
                    'webserver', 'EXPOSE_HOSTNAME', fallback=True) else 'redact',
                'navbar_color': conf.get('webserver', 'NAVBAR_COLOR'),
                'log_fetch_delay_sec': conf.getint(
                    'webserver', 'log_fetch_delay_sec', fallback=2),
                'log_auto_tailing_offset': conf.getint(
                    'webserver', 'log_auto_tailing_offset', fallback=30),
                'log_animation_speed': conf.getint(
                    'webserver', 'log_animation_speed', fallback=1000),
                'state_color_mapping': STATE_COLORS
            }

            if 'analytics_tool' in conf.getsection('webserver'):
                globals.update({
                    'analytics_tool': conf.get('webserver', 'ANALYTICS_TOOL'),
                    'analytics_id': conf.get('webserver', 'ANALYTICS_ID')
                })

            return globals

        @app.teardown_appcontext
        def shutdown_session(exception=None):
            settings.Session.remove()

        @app.after_request
        def apply_caching(response):
            _x_frame_enabled = conf.getboolean('webserver', 'X_FRAME_ENABLED', fallback=True)
            if not _x_frame_enabled:
                response.headers["X-Frame-Options"] = "DENY"
            return response

        @app.before_request
        def make_session_permanent():
            flask_session.permanent = True

    return app, appbuilder

--- a/airflow/www_rbac/app.py
+++ b/airflow/www_rbac/app.py
@@ -14,6 +14,11 @@
     app.secret_key = conf.get('webserver', 'SECRET_KEY')
     app.config['PERMANENT_SESSION_LIFETIME'] = timedelta(minutes=settings.get_session_lifetime_config())

+    if conf.get('webserver', 'SECRET_KEY') == "temporary_key":
+        app.secret_key = os.urandom(16)
+    else:
+        app.secret_key = conf.get('webserver', 'SECRET_KEY')
+
     app.config.from_pyfile(settings.WEBSERVER_CONFIG, silent=True)
     app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
     app.config['APP_NAME'] = app_name


Wagtail is an open source content management system built on Django. A user with a limited-permission editor account for the Wagtail admin can make a direct URL request to the admin view that handles bulk actions on user accounts. While authentication rules prevent the user from making any changes, the error message discloses the display names of user accounts, and by modifying URL parameters, the user can retrieve the display name for any user. The vulnerability is not exploitable by an ordinary site visitor without access to the Wagtail admin. Patched versions have been released as Wagtail 4.1.8 (LTS), 5.0.5 and 5.1.3. The fix is also included in Release Candidate 1 of the forthcoming Wagtail 5.2 release. Users are advised to upgrade. There are no known workarounds for this vulnerability.

Insertion of Sensitive Information into Log File

The product writes sensitive information to a log file.

class UserBulkAction(BulkAction):
    models = [get_user_model()]

User = get_user_model()

class UserBulkAction(PermissionCheckedMixin, BulkAction):
    models = [User]
    permission_policy = ModelPermissionPolicy(User)
    any_permission_required = ["add", "change", "delete"]

--- a/wagtail/users/views/bulk_actions/user_bulk_action.py
+++ b/wagtail/users/views/bulk_actions/user_bulk_action.py
@@ -1,3 +1,7 @@
+User = get_user_model()

-class UserBulkAction(BulkAction):
-    models = [get_user_model()]
+
+class UserBulkAction(PermissionCheckedMixin, BulkAction):
+    models = [User]
+    permission_policy = ModelPermissionPolicy(User)
+    any_permission_required = ["add", "change", "delete"]

#!/bin/bash
# From ghcr.io/anonymous2578-data/cve-2023-45809:latest
# bash /workspace/fix-run.sh
set -e

cd /workspace/wagtail
git apply --whitespace=nowarn /workspace/test.patch /workspace/fix.patch
/workspace/PoC_env/CVE-2023-45809/bin/python runtests.py wagtail.users.tests.test_bulk_actions.test_bulk_delete.TestUserDeleteView.test_user_permissions_required

#!/bin/bash
# From ghcr.io/anonymous2578-data/cve-2023-45809:latest
# bash /workspace/unit_test.sh
set -e

cd /workspace/wagtail
git apply --whitespace=nowarn /workspace/fix.patch
/workspace/PoC_env/CVE-2023-45809/bin/python runtests.py wagtail.users.tests.test_bulk_actions.test_bulk_delete


ceph-deploy before 1.5.23 uses weak permissions (644) for ceph/ceph.client.admin.keyring, which allows local users to obtain sensitive information by reading the file.

Exposure of Sensitive Information to an Unauthorized Actor

The product exposes sensitive information to an actor that is not explicitly authorized to have access to that information.

def gatherkeys(args):
    # client.admin
    keyring = '/etc/ceph/{cluster}.client.admin.keyring'.format(
        cluster=args.cluster)
    r = fetch_file(
        args=args,
        frompath=keyring,
        topath='{cluster}.client.admin.keyring'.format(
            cluster=args.cluster),
        _hosts=args.mon,
        )
    if not r:
        raise exc.KeyNotFoundError(keyring, args.mon)

    # mon.
    keyring = '/var/lib/ceph/mon/{cluster}-{{hostname}}/keyring'.format(
        cluster=args.cluster)
    r = fetch_file(
        args=args,
        frompath=keyring,
        topath='{cluster}.mon.keyring'.format(cluster=args.cluster),
        _hosts=args.mon,
        )
    if not r:
        raise exc.KeyNotFoundError(keyring, args.mon)

    # bootstrap
    for what in ['osd', 'mds', 'rgw']:
        keyring = '/var/lib/ceph/bootstrap-{what}/{cluster}.keyring'.format(
            what=what,
            cluster=args.cluster)
        r = fetch_file(
            args=args,
            frompath=keyring,
            topath='{cluster}.bootstrap-{what}.keyring'.format(
                cluster=args.cluster,
                what=what),
            _hosts=args.mon,
            )
        if not r:
            if what in ['osd', 'mds']:
                raise exc.KeyNotFoundError(keyring, args.mon)
            else:
                LOG.warning(("No RGW bootstrap key found. Will not be able to "
                             "deploy RGW daemons"))

def new_mon_keyring(args):
    LOG.debug('Creating a random mon key...')
    mon_keyring = '[mon.]\nkey = %s\ncaps mon = allow *\n' % generate_auth_key()

    keypath = '{name}.mon.keyring'.format(
        name=args.cluster,
        )

    LOG.debug('Writing monitor keyring to %s...', keypath)
    tmp = '%s.tmp' % keypath
    with file(tmp, 'w') as f:
        f.write(mon_keyring)
    try:
        os.rename(tmp, keypath)
    except OSError as e:
        if e.errno == errno.EEXIST:
            raise exc.ClusterExistsError(keypath)
        else:
            raise

def gatherkeys(args):
    oldmask = os.umask(077)
    try:
        # client.admin
        keyring = '/etc/ceph/{cluster}.client.admin.keyring'.format(
            cluster=args.cluster)
        r = fetch_file(
            args=args,
            frompath=keyring,
            topath='{cluster}.client.admin.keyring'.format(
                cluster=args.cluster),
            _hosts=args.mon,
            )
        if not r:
            raise exc.KeyNotFoundError(keyring, args.mon)

        # mon.
        keyring = '/var/lib/ceph/mon/{cluster}-{{hostname}}/keyring'.format(
            cluster=args.cluster)
        r = fetch_file(
            args=args,
            frompath=keyring,
            topath='{cluster}.mon.keyring'.format(cluster=args.cluster),
            _hosts=args.mon,
            )
        if not r:
            raise exc.KeyNotFoundError(keyring, args.mon)

        # bootstrap
        for what in ['osd', 'mds', 'rgw']:
            keyring = '/var/lib/ceph/bootstrap-{what}/{cluster}.keyring'.format(
                what=what,
                cluster=args.cluster)
            r = fetch_file(
                args=args,
                frompath=keyring,
                topath='{cluster}.bootstrap-{what}.keyring'.format(
                    cluster=args.cluster,
                    what=what),
                _hosts=args.mon,
                )
            if not r:
                if what in ['osd', 'mds']:
                    raise exc.KeyNotFoundError(keyring, args.mon)
                else:
                    LOG.warning(("No RGW bootstrap key found. Will not be able to "
                                 "deploy RGW daemons"))
    finally:
        os.umask(oldmask)

def new_mon_keyring(args):
    LOG.debug('Creating a random mon key...')
    mon_keyring = '[mon.]\nkey = %s\ncaps mon = allow *\n' % generate_auth_key()

    keypath = '{name}.mon.keyring'.format(
        name=args.cluster,
        )
    oldmask = os.umask(077)
    LOG.debug('Writing monitor keyring to %s...', keypath)
    try:
        tmp = '%s.tmp' % keypath
        with open(tmp, 'w', 0600) as f:
            f.write(mon_keyring)
        try:
            os.rename(tmp, keypath)
        except OSError as e:
            if e.errno == errno.EEXIST:
                raise exc.ClusterExistsError(keypath)
            else:
                raise
    finally:
        os.umask(oldmask)

--- a/ceph_deploy/gatherkeys.py
+++ b/ceph_deploy/gatherkeys.py
@@ -1,45 +1,49 @@
 def gatherkeys(args):
-    # client.admin
-    keyring = '/etc/ceph/{cluster}.client.admin.keyring'.format(
-        cluster=args.cluster)
-    r = fetch_file(
-        args=args,
-        frompath=keyring,
-        topath='{cluster}.client.admin.keyring'.format(
-            cluster=args.cluster),
-        _hosts=args.mon,
-        )
-    if not r:
-        raise exc.KeyNotFoundError(keyring, args.mon)
-
-    # mon.
-    keyring = '/var/lib/ceph/mon/{cluster}-{{hostname}}/keyring'.format(
-        cluster=args.cluster)
-    r = fetch_file(
-        args=args,
-        frompath=keyring,
-        topath='{cluster}.mon.keyring'.format(cluster=args.cluster),
-        _hosts=args.mon,
-        )
-    if not r:
-        raise exc.KeyNotFoundError(keyring, args.mon)
-
-    # bootstrap
-    for what in ['osd', 'mds', 'rgw']:
-        keyring = '/var/lib/ceph/bootstrap-{what}/{cluster}.keyring'.format(
-            what=what,
+    oldmask = os.umask(077)
+    try:
+        # client.admin
+        keyring = '/etc/ceph/{cluster}.client.admin.keyring'.format(
             cluster=args.cluster)
         r = fetch_file(
             args=args,
             frompath=keyring,
-            topath='{cluster}.bootstrap-{what}.keyring'.format(
-                cluster=args.cluster,
-                what=what),
+            topath='{cluster}.client.admin.keyring'.format(
+                cluster=args.cluster),
             _hosts=args.mon,
             )
         if not r:
-            if what in ['osd', 'mds']:
-                raise exc.KeyNotFoundError(keyring, args.mon)
-            else:
-                LOG.warning(("No RGW bootstrap key found. Will not be able to "
-                             "deploy RGW daemons"))
+            raise exc.KeyNotFoundError(keyring, args.mon)
+
+        # mon.
+        keyring = '/var/lib/ceph/mon/{cluster}-{{hostname}}/keyring'.format(
+            cluster=args.cluster)
+        r = fetch_file(
+            args=args,
+            frompath=keyring,
+            topath='{cluster}.mon.keyring'.format(cluster=args.cluster),
+            _hosts=args.mon,
+            )
+        if not r:
+            raise exc.KeyNotFoundError(keyring, args.mon)
+
+        # bootstrap
+        for what in ['osd', 'mds', 'rgw']:
+            keyring = '/var/lib/ceph/bootstrap-{what}/{cluster}.keyring'.format(
+                what=what,
+                cluster=args.cluster)
+            r = fetch_file(
+                args=args,
+                frompath=keyring,
+                topath='{cluster}.bootstrap-{what}.keyring'.format(
+                    cluster=args.cluster,
+                    what=what),
+                _hosts=args.mon,
+                )
+            if not r:
+                if what in ['osd', 'mds']:
+                    raise exc.KeyNotFoundError(keyring, args.mon)
+                else:
+                    LOG.warning(("No RGW bootstrap key found. Will not be able to "
+                                 "deploy RGW daemons"))
+    finally:
+        os.umask(oldmask)

--- a/ceph_deploy/new.py
+++ b/ceph_deploy/new.py
@@ -5,15 +5,18 @@
     keypath = '{name}.mon.keyring'.format(
         name=args.cluster,
         )
-
+    oldmask = os.umask(077)
     LOG.debug('Writing monitor keyring to %s...', keypath)
-    tmp = '%s.tmp' % keypath
-    with file(tmp, 'w') as f:
-        f.write(mon_keyring)
     try:
-        os.rename(tmp, keypath)
-    except OSError as e:
-        if e.errno == errno.EEXIST:
-            raise exc.ClusterExistsError(keypath)
-        else:
-            raise
+        tmp = '%s.tmp' % keypath
+        with open(tmp, 'w', 0600) as f:
+            f.write(mon_keyring)
+        try:
+            os.rename(tmp, keypath)
+        except OSError as e:
+            if e.errno == errno.EEXIST:
+                raise exc.ClusterExistsError(keypath)
+            else:
+                raise
+    finally:
+        os.umask(oldmask)


Open Redirect in GitHub repository medialize/uri.js prior to 1.19.10.

  URI.parse = function(string, parts) {
    var pos;
    if (!parts) {
      parts = {
        preventInvalidHostname: URI.preventInvalidHostname
      };
    }

    string = string.replace(URI.leading_whitespace_expression, '')

    // [protocol"://"[username[":"password]"@"]hostname[":"port]"/"?][path]["?"querystring]["#"fragment]

    // extract fragment
    pos = string.indexOf('#');
    if (pos > -1) {
      // escaping?
      parts.fragment = string.substring(pos + 1) || null;
      string = string.substring(0, pos);
    }

    // extract query
    pos = string.indexOf('?');
    if (pos > -1) {
      // escaping?
      parts.query = string.substring(pos + 1) || null;
      string = string.substring(0, pos);
    }

    // slashes and backslashes have lost all meaning for the web protocols (https, http, wss, ws)
    string = string.replace(/^(https?|ftp|wss?)?:[/\\]*/i, '$1://');

    // extract protocol
    if (string.substring(0, 2) === '//') {
      // relative-scheme
      parts.protocol = null;
      string = string.substring(2);
      // extract "user:pass@host:port"
      string = URI.parseAuthority(string, parts);
    } else {
      pos = string.indexOf(':');
      if (pos > -1) {
        parts.protocol = string.substring(0, pos) || null;
        if (parts.protocol && !parts.protocol.match(URI.protocol_expression)) {
          // : may be within the path
          parts.protocol = undefined;
        } else if (string.substring(pos + 1, pos + 3).replace(/\\/g, '/') === '//') {
          string = string.substring(pos + 3);

          // extract "user:pass@host:port"
          string = URI.parseAuthority(string, parts);
        } else {
          string = string.substring(pos + 1);
          parts.urn = true;
        }
      }
    }

    // what's left must be the path
    parts.path = string;

    // and we're done
    return parts;
  };

  URI.parse = function(string, parts) {
    var pos;
    if (!parts) {
      parts = {
        preventInvalidHostname: URI.preventInvalidHostname
      };
    }

    string = string.replace(URI.leading_whitespace_expression, '')

    // [protocol"://"[username[":"password]"@"]hostname[":"port]"/"?][path]["?"querystring]["#"fragment]

    // extract fragment
    pos = string.indexOf('#');
    if (pos > -1) {
      // escaping?
      parts.fragment = string.substring(pos + 1) || null;
      string = string.substring(0, pos);
    }

    // extract query
    pos = string.indexOf('?');
    if (pos > -1) {
      // escaping?
      parts.query = string.substring(pos + 1) || null;
      string = string.substring(0, pos);
    }

    // slashes and backslashes have lost all meaning for the web protocols (https, http, wss, ws)
    string = string.replace(/^(https?|ftp|wss?)?:+[/\\]*/i, '$1://');

    // extract protocol
    if (string.substring(0, 2) === '//') {
      // relative-scheme
      parts.protocol = null;
      string = string.substring(2);
      // extract "user:pass@host:port"
      string = URI.parseAuthority(string, parts);
    } else {
      pos = string.indexOf(':');
      if (pos > -1) {
        parts.protocol = string.substring(0, pos) || null;
        if (parts.protocol && !parts.protocol.match(URI.protocol_expression)) {
          // : may be within the path
          parts.protocol = undefined;
        } else if (string.substring(pos + 1, pos + 3).replace(/\\/g, '/') === '//') {
          string = string.substring(pos + 3);

          // extract "user:pass@host:port"
          string = URI.parseAuthority(string, parts);
        } else {
          string = string.substring(pos + 1);
          parts.urn = true;
        }
      }
    }

    // what's left must be the path
    parts.path = string;

    // and we're done
    return parts;
  };

--- a/src/URI.js
+++ b/src/URI.js
@@ -27,7 +27,7 @@
     }

     // slashes and backslashes have lost all meaning for the web protocols (https, http, wss, ws)
-    string = string.replace(/^(https?|ftp|wss?)?:[/\\]*/i, '$1://');
+    string = string.replace(/^(https?|ftp|wss?)?:+[/\\]*/i, '$1://');

     // extract protocol
     if (string.substring(0, 2) === '//') {


node/utils/ExportEtherpad.js in Etherpad 1.5.x before 1.5.2 might allow remote attackers to obtain sensitive information by leveraging an improper substring check when exporting a padID.

exports.getPadRaw = function(padId, callback){
  async.waterfall([
  function(cb){

    // Get the Pad available content keys
    db.findKeys("pad:"+padId+"*", null, function(err,records){
      if(!err){
        cb(err, records);
      }
    })
  },
  function(records, cb){
    var data = {};

    async.forEachSeries(Object.keys(records), function(key, r){

      // For each piece of info about a pad.
      db.get(records[key], function(err, entry){
        data[records[key]] = entry;

        // Get the Pad Authors
        if(entry.pool && entry.pool.numToAttrib){
          var authors = entry.pool.numToAttrib;
          async.forEachSeries(Object.keys(authors), function(k, c){
            if(authors[k][0] === "author"){
              var authorId = authors[k][1];

              // Get the author info
              db.get("globalAuthor:"+authorId, function(e, authorEntry){
                if(authorEntry && authorEntry.padIDs) authorEntry.padIDs = padId;
                if(!e) data["globalAuthor:"+authorId] = authorEntry;
              });

            }
            // console.log("authorsK", authors[k]);
            c(null);
          });
        }
        r(null); // callback;
      });
    }, function(err){
      cb(err, data);
    })
  }
  ], function(err, data){
    callback(null, data);
  });
}

exports.getPadRaw = function(padId, callback){
  async.waterfall([
  function(cb){

    // Get the Pad
    db.findKeys("pad:"+padId, null, function(err,padcontent){
      if(!err){
        cb(err, padcontent);
      }
    })
  },
  function(padcontent,cb){

    // Get the Pad available content keys
    db.findKeys("pad:"+padId+":*", null, function(err,records){
      if(!err){
        for (var key in padcontent) { records.push(padcontent[key]);}
        cb(err, records);
      }
    })
  },
  function(records, cb){
    var data = {};

    async.forEachSeries(Object.keys(records), function(key, r){

      // For each piece of info about a pad.
      db.get(records[key], function(err, entry){
        data[records[key]] = entry;

        // Get the Pad Authors
        if(entry.pool && entry.pool.numToAttrib){
          var authors = entry.pool.numToAttrib;
          async.forEachSeries(Object.keys(authors), function(k, c){
            if(authors[k][0] === "author"){
              var authorId = authors[k][1];

              // Get the author info
              db.get("globalAuthor:"+authorId, function(e, authorEntry){
                if(authorEntry && authorEntry.padIDs) authorEntry.padIDs = padId;
                if(!e) data["globalAuthor:"+authorId] = authorEntry;
              });

            }
            // console.log("authorsK", authors[k]);
            c(null);
          });
        }
        r(null); // callback;
      });
    }, function(err){
      cb(err, data);
    })
  }
  ], function(err, data){
    callback(null, data);
  });
}

--- a/src/node/utils/ExportEtherpad.js
+++ b/src/node/utils/ExportEtherpad.js
@@ -2,9 +2,19 @@
   async.waterfall([
   function(cb){

+    // Get the Pad
+    db.findKeys("pad:"+padId, null, function(err,padcontent){
+      if(!err){
+        cb(err, padcontent);
+      }
+    })
+  },
+  function(padcontent,cb){
+
     // Get the Pad available content keys
-    db.findKeys("pad:"+padId+"*", null, function(err,records){
+    db.findKeys("pad:"+padId+":*", null, function(err,records){
       if(!err){
+        for (var key in padcontent) { records.push(padcontent[key]);}
         cb(err, records);
       }
     })


Lif Auth Server is a server for validating logins, managing information, and account recovery for Lif Accounts. The issue relates to the `get_pfp` and `get_banner` routes on Auth Server. The issue is that there is no check to ensure that the file that Auth Server is receiving through these URLs is correct. This could allow an attacker access to files they shouldn't have access to. This issue has been patched in version 1.4.0.

async def get_pfp(username: str):
    """
    ## Get User Avatar (Profile Picture)
    Allows services to get the avatar (profile picture) of a specified account.

    ### Parameters:
    - **username (str):** The username for the account.

    ### Returns:
    - **file:** The avatar the service requested.
    """
    # Checks if the user has a profile pic uploaded
    if os.path.isfile(f"user_images/pfp/{username}"):
        return FileResponse(f"user_images/pfp/{username}", media_type='image/gif')
    else:
        # Returns default image if none is uploaded
        return FileResponse(f'{assets_folder}/default_pfp.png', media_type='image/gif')

async def get_banner(username: str):
    """
    ## Get User Banner
    Allows services to get the account banner of a specified account.

    ### Parameters:
    - **username (str):** The username for the account.

    ### Returns:
    - **file:** The banner the service requested.
    """
    # Checks if the user has a profile pic uploaded
    if os.path.isfile(f"user_images/banner/{username}"):
        return FileResponse(f"user_images/banner/{username}", media_type='image/gif')
    else:
        # Returns default image if none is uploaded
        return FileResponse(f'{assets_folder}/default_banner.png', media_type='image/gif')

async def get_pfp(username: str):
    """
    ## Get User Avatar (Profile Picture)
    Allows services to get the avatar (profile picture) of a specified account.

    ### Parameters:
    - **username (str):** The username for the account.

    ### Returns:
    - **file:** The avatar the service requested.
    """
    # Sanitize and validate the username variable (Example: alphanumeric characters allowed)
    if not username.isalnum():
        # Handle invalid input (username contains non-alphanumeric characters)
        return FileResponse(f'{assets_folder}/default_pfp.png', media_type='image/gif')

    # Construct the file path using the sanitized username
    banner_path = f"user_images/pfp/{username}"

    # Check if the file exists and is a regular file
    if os.path.isfile(banner_path):
        return FileResponse(banner_path, media_type='image/gif')
    else:
        # Return default image if the user's banner doesn't exist
        return FileResponse(f'{assets_folder}/default_pfp.png', media_type='image/gif')

async def get_banner(username: str):
    """
    ## Get User Banner
    Allows services to get the account banner of a specified account.

    ### Parameters:
    - **username (str):** The username for the account.

    ### Returns:
    - **file:** The banner the service requested.
    """
    # Sanitize and validate the username variable (Example: alphanumeric characters allowed)
    if not username.isalnum():
        # Handle invalid input (username contains non-alphanumeric characters)
        return FileResponse(f'{assets_folder}/default_banner.png', media_type='image/gif')

    # Construct the file path using the sanitized username
    banner_path = f"user_images/banner/{username}"

    # Check if the file exists and is a regular file
    if os.path.isfile(banner_path):
        return FileResponse(banner_path, media_type='image/gif')
    else:
        # Return default image if the user's banner doesn't exist
        return FileResponse(f'{assets_folder}/default_banner.png', media_type='image/gif')

--- a/src/auth_server.py
+++ b/src/auth_server.py
@@ -9,9 +9,17 @@
     ### Returns:
     - **file:** The avatar the service requested.
     """
-    # Checks if the user has a profile pic uploaded
-    if os.path.isfile(f"user_images/pfp/{username}"):
-        return FileResponse(f"user_images/pfp/{username}", media_type='image/gif')
+    # Sanitize and validate the username variable (Example: alphanumeric characters allowed)
+    if not username.isalnum():
+        # Handle invalid input (username contains non-alphanumeric characters)
+        return FileResponse(f'{assets_folder}/default_pfp.png', media_type='image/gif')
+
+    # Construct the file path using the sanitized username
+    banner_path = f"user_images/pfp/{username}"
+
+    # Check if the file exists and is a regular file
+    if os.path.isfile(banner_path):
+        return FileResponse(banner_path, media_type='image/gif')
     else:
-        # Returns default image if none is uploaded
+        # Return default image if the user's banner doesn't exist
         return FileResponse(f'{assets_folder}/default_pfp.png', media_type='image/gif')

--- a/src/auth_server.py
+++ b/src/auth_server.py
@@ -9,9 +9,17 @@
     ### Returns:
     - **file:** The banner the service requested.
     """
-    # Checks if the user has a profile pic uploaded
-    if os.path.isfile(f"user_images/banner/{username}"):
-        return FileResponse(f"user_images/banner/{username}", media_type='image/gif')
+    # Sanitize and validate the username variable (Example: alphanumeric characters allowed)
+    if not username.isalnum():
+        # Handle invalid input (username contains non-alphanumeric characters)
+        return FileResponse(f'{assets_folder}/default_banner.png', media_type='image/gif')
+
+    # Construct the file path using the sanitized username
+    banner_path = f"user_images/banner/{username}"
+
+    # Check if the file exists and is a regular file
+    if os.path.isfile(banner_path):
+        return FileResponse(banner_path, media_type='image/gif')
     else:
-        # Returns default image if none is uploaded
+        # Return default image if the user's banner doesn't exist
         return FileResponse(f'{assets_folder}/default_banner.png', media_type='image/gif')


localhost-now node module suffers from a Path Traversal vulnerability due to lack of validation of file, which allows a malicious user to read content of any file with known path.

exports.start = function(args) {
	var port = parseInt(args[0]) ? args[0] : 1337;

	http.createServer(function(req, res) {
		var url = req.url;

		if (url.indexOf('?') != -1) {
			url = url.split('?')[0];
		}

		var file = url === "/" ? "/index.html" : url;

		fs.readFile(path.normalize(process.cwd()) + file, function(err, data) {
			if (!!err) {
				console.error('Error loading : '+ url);
				res.writeHead(404);
				res.end();
			}
			else {
				var type = path.extname(file);

				if (type === ".js") {
	        contentType = 'application/javascript';
				}
				else {
					contentType = "text/"+ type.slice(1, type.length);
				}

				res.setHeader('content-type', contentType);
				res.end(data);
			}

		});

	}).listen(port);
	process.stdout.write("\033[33mWeb Server started on localhost:"+ port +" \033[39m\n");
}

exports.start = function(args) {
  const port = parseInt(args[0]) ? args[0] : 1337

  http
    .createServer(function(req, res) {
      const url = req.url

      if (url.indexOf('?') != -1) {
        url = url.split('?')[0]
      }

      const file = url === '/' ? '/index.html' : url.replace(/(\.\.[\/\\])+/g, '')
      const rootPath = path.normalize(process.cwd())

      fs.readFile(`${rootPath}${file}`, (err, data) => {
        if (!!err) {
          console.error('Error loading : ' + url)
          res.writeHead(404)
          res.end()
        } else {
          var type = path.extname(file)

          if (type === '.js') {
            contentType = 'application/javascript'
          } else {
            contentType = 'text/' + type.slice(1, type.length)
          }

          res.setHeader('content-type', contentType)
          res.end(data)
        }
      })
    })
    .listen(port)
  process.stdout.write('\033[33mWeb Server started on localhost:' + port + ' \033[39m\n')
}

--- a/lib/app.js
+++ b/lib/app.js
@@ -1,38 +1,36 @@
 exports.start = function(args) {
-	var port = parseInt(args[0]) ? args[0] : 1337;
+  const port = parseInt(args[0]) ? args[0] : 1337

-	http.createServer(function(req, res) {
-		var url = req.url;
+  http
+    .createServer(function(req, res) {
+      const url = req.url

-		if (url.indexOf('?') != -1) {
-			url = url.split('?')[0];
-		}
+      if (url.indexOf('?') != -1) {
+        url = url.split('?')[0]
+      }

-		var file = url === "/" ? "/index.html" : url;
+      const file = url === '/' ? '/index.html' : url.replace(/(\.\.[\/\\])+/g, '')
+      const rootPath = path.normalize(process.cwd())

-		fs.readFile(path.normalize(process.cwd()) + file, function(err, data) {
-			if (!!err) {
-				console.error('Error loading : '+ url);
-				res.writeHead(404);
-				res.end();
-			}
-			else {
-				var type = path.extname(file);
+      fs.readFile(`${rootPath}${file}`, (err, data) => {
+        if (!!err) {
+          console.error('Error loading : ' + url)
+          res.writeHead(404)
+          res.end()
+        } else {
+          var type = path.extname(file)

-				if (type === ".js") {
-	        contentType = 'application/javascript';
-				}
-				else {
-					contentType = "text/"+ type.slice(1, type.length);
-				}
+          if (type === '.js') {
+            contentType = 'application/javascript'
+          } else {
+            contentType = 'text/' + type.slice(1, type.length)
+          }

-				res.setHeader('content-type', contentType);
-				res.end(data);
-			}
-
-
-		});
-
-	}).listen(port);
-	process.stdout.write("\033[33mWeb Server started on localhost:"+ port +" \033[39m\n");
+          res.setHeader('content-type', contentType)
+          res.end(data)
+        }
+      })
+    })
+    .listen(port)
+  process.stdout.write('\033[33mWeb Server started on localhost:' + port + ' \033[39m\n')
 }


HashiCorp’s go-getter library can be coerced into executing Git update on an existing maliciously modified Git Configuration, potentially leading to arbitrary code execution.

Improper Neutralization of Special Elements used in a Command ('Command Injection')

The product constructs all or part of a command using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the intended command when it is sent to a downstream component.

Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection')

The product constructs all or part of an OS command using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the intended OS command when it is sent to a downstream component.

func (g *GitGetter) clone(ctx context.Context, dst, sshKeyFile string, u *url.URL, ref string, depth int) error {
	args := []string{"clone"}

	originalRef := ref // we handle an unspecified ref differently than explicitly selecting the default branch below
	if ref == "" {
		ref = findRemoteDefaultBranch(ctx, u)
	}
	if depth > 0 {
		args = append(args, "--depth", strconv.Itoa(depth))
		args = append(args, "--branch", ref)
	}
	args = append(args, u.String(), dst)

	cmd := exec.CommandContext(ctx, "git", args...)
	setupGitEnv(cmd, sshKeyFile)
	err := getRunCommand(cmd)
	if err != nil {
		if depth > 0 && originalRef != "" {
			// If we're creating a shallow clone then the given ref must be
			// a named ref (branch or tag) rather than a commit directly.
			// We can't accurately recognize the resulting error here without
			// hard-coding assumptions about git's human-readable output, but
			// we can at least try a heuristic.
			if gitCommitIDRegex.MatchString(originalRef) {
				return fmt.Errorf("%w (note that setting 'depth' requires 'ref' to be a branch or tag name)", err)
			}
		}
		return err
	}

	if depth < 1 && originalRef != "" {
		// If we didn't add --depth and --branch above then we will now be
		// on the remote repository's default branch, rather than the selected
		// ref, so we'll need to fix that before we return.
		return g.checkout(ctx, dst, originalRef)
	}
	return nil
}

func findRemoteDefaultBranch(ctx context.Context, u *url.URL) string {
	var stdoutbuf bytes.Buffer
	cmd := exec.CommandContext(ctx, "git", "ls-remote", "--symref", u.String(), "HEAD")
	cmd.Stdout = &stdoutbuf
	err := cmd.Run()
	matches := lsRemoteSymRefRegexp.FindStringSubmatch(stdoutbuf.String())
	if err != nil || matches == nil {
		return "master"
	}
	return matches[len(matches)-1]
}

func (g *GitGetter) clone(ctx context.Context, dst, sshKeyFile string, u *url.URL, ref string, depth int) error {
	args := []string{"clone"}

	originalRef := ref // we handle an unspecified ref differently than explicitly selecting the default branch below
	if ref == "" {
		ref = findRemoteDefaultBranch(ctx, u)
	}
	if depth > 0 {
		args = append(args, "--depth", strconv.Itoa(depth))
		args = append(args, "--branch", ref)
	}
	args = append(args, "--", u.String(), dst)

	cmd := exec.CommandContext(ctx, "git", args...)
	setupGitEnv(cmd, sshKeyFile)
	err := getRunCommand(cmd)
	if err != nil {
		if depth > 0 && originalRef != "" {
			// If we're creating a shallow clone then the given ref must be
			// a named ref (branch or tag) rather than a commit directly.
			// We can't accurately recognize the resulting error here without
			// hard-coding assumptions about git's human-readable output, but
			// we can at least try a heuristic.
			if gitCommitIDRegex.MatchString(originalRef) {
				return fmt.Errorf("%w (note that setting 'depth' requires 'ref' to be a branch or tag name)", err)
			}
		}
		return err
	}

	if depth < 1 && originalRef != "" {
		// If we didn't add --depth and --branch above then we will now be
		// on the remote repository's default branch, rather than the selected
		// ref, so we'll need to fix that before we return.
		return g.checkout(ctx, dst, originalRef)
	}
	return nil
}

func findRemoteDefaultBranch(ctx context.Context, u *url.URL) string {
	var stdoutbuf bytes.Buffer
	cmd := exec.CommandContext(ctx, "git", "ls-remote", "--symref", "--", u.String(), "HEAD")
	cmd.Stdout = &stdoutbuf
	err := cmd.Run()
	matches := lsRemoteSymRefRegexp.FindStringSubmatch(stdoutbuf.String())
	if err != nil || matches == nil {
		return "master"
	}
	return matches[len(matches)-1]
}

--- a/get_git.go
+++ b/get_git.go
@@ -9,7 +9,7 @@
 		args = append(args, "--depth", strconv.Itoa(depth))
 		args = append(args, "--branch", ref)
 	}
-	args = append(args, u.String(), dst)
+	args = append(args, "--", u.String(), dst)

 	cmd := exec.CommandContext(ctx, "git", args...)
 	setupGitEnv(cmd, sshKeyFile)

--- a/get_git.go
+++ b/get_git.go
@@ -1,6 +1,6 @@
 func findRemoteDefaultBranch(ctx context.Context, u *url.URL) string {
 	var stdoutbuf bytes.Buffer
-	cmd := exec.CommandContext(ctx, "git", "ls-remote", "--symref", u.String(), "HEAD")
+	cmd := exec.CommandContext(ctx, "git", "ls-remote", "--symref", "--", u.String(), "HEAD")
 	cmd.Stdout = &stdoutbuf
 	err := cmd.Run()
 	matches := lsRemoteSymRefRegexp.FindStringSubmatch(stdoutbuf.String())

#!/bin/bash
# From ghcr.io/anonymous2578-data/cve-2024-6257:latest
# bash /workspace/fix-run.sh
set -e

cd /workspace/go-getter
git apply --whitespace=nowarn /workspace/test.patch /workspace/fix.patch
go test   -timeout 30s -run ^TestGitGetter_BadRemoteUrl$ github.com/hashicorp/go-getter

#!/bin/bash
# From ghcr.io/anonymous2578-data/cve-2024-6257:latest
# bash /workspace/unit_test.sh
set -e

cd /workspace/go-getter
git apply --whitespace=nowarn /workspace/fix.patch
go test -timeout 30s -run '^(TestGitGetter_gitVersion|TestGitGetter_tag|TestGitGetter_sshSCPStyleInvalidScheme|TestGitGetter_shallowClone|TestGitGetter_setupGitEnvWithNoKeyFile|TestGitGetter_commitID|TestGitGetter_branch|TestGitGetter_shallowCloneWithTag|TestGitGetter_GetFile|TestGitGetter_submodule|TestGitGetter_subdirectory|TestGitGetter_shallowCloneWithCommitID|TestGitGetter_setupGitEnv_sshKey|TestGitGetter_impl|TestGitGetter|TestGitGetter_branchUpdate|TestGitGetter_subdirectory_symlink|TestGitGetter_remoteWithoutMaster|TestGitGetter_setupGitEnvWithExisting_sshKey)$' github.com/hashicorp/go-getter