The pdfinfojs NPM module versions <= 0.3.6 has a command injection vulnerability that allows an attacker to execute arbitrary commands on the victim's machine.

function pdfinfo (filename, options) {
  this.options = options || {};
  this.options.additional = ['"' + filename + '"'];

  pdfinfo.prototype.add_options = function(optionArray) {
    if (typeof optionArray.length !== undefined) {
        var self = this;
        optionArray.forEach(function(el) {
          if (el.indexOf(' ') > 0) {
            var values = el.split(' ');
            self.options.additional.push(values[0], values[1]);
          } else {
            self.options.additional.push(el);
          }
        });
    }
    return this;
  };

  pdfinfo.prototype.getInfoSync = function() {
    const self = this;
    try {
    	let data = execSync('pdfinfo ' + self.options.additional.join(' ')).toString('utf8');
        return utils.parse(data);
    } catch(err) {
        throw new Error("pdfinfo error: "+ err.msg);
    }
  }

  pdfinfo.prototype.getInfo = function(cb) {
    let self = this;
    let child = exec('pdfinfo ' + self.options.additional.join(' '), function(error, stdout, stderr) {
      if (!error) {
        let data = utils.parse(stdout);
        if (cb && typeof cb === "function") {
          cb(null, data, self.options.additional);
        }
      }
      else {
        console.info('pdfinfo (poppler-utils) is missing. Hint: sudo apt-get install poppler-utils');
        if (cb && typeof cb === "function") {
          cb(new Error(stderr), null, self.options.addtional);
        }
      }
    });
  }

  pdfinfo.prototype.error = function(callback) {
    this.options.error = callback;
    return this;
  };

  pdfinfo.prototype.success = function(callback) {
    this.options.success = callback;
    return this;
  };
}

function pdfinfo (filename, options) {
  this.options = options || {};
  this.options.additional = [filename];

  pdfinfo.prototype.add_options = function(optionArray) {
    if (typeof optionArray.length !== undefined) {
        var self = this;
        optionArray.forEach(function(el) {
          if (el.indexOf(' ') > 0) {
            var values = el.split(' ');
            self.options.additional.push(values[0], values[1]);
          } else {
            self.options.additional.push(el);
          }
        });
    }
    return this;
  };

  pdfinfo.prototype.getInfoSync = function() {
    const self = this;
    try {
    	let data = execFileSync('pdfinfo', self.options.additional).toString('utf8');
        return utils.parse(data);
    } catch(err) {
        throw new Error("pdfinfo error: "+ err.msg);
    }
  }

  pdfinfo.prototype.getInfo = function(cb) {
    let self = this;
    let child = execFile('pdfinfo', self.options.additional, (error, stdout, stderr) => {
      if (!error) {
        let data = utils.parse(stdout);
        if (cb && typeof cb === "function") {
          cb(null, data, self.options.additional);
        }
      }
      else {
        console.info('pdfinfo (poppler-utils) is missing. Hint: sudo apt-get install poppler-utils');
        if (cb && typeof cb === "function") {
          cb(new Error(stderr), null, self.options.addtional);
        }
      }
    });
  }

  pdfinfo.prototype.error = function(callback) {
    this.options.error = callback;
    return this;
  };

  pdfinfo.prototype.success = function(callback) {
    this.options.success = callback;
    return this;
  };
}

--- a/lib/pdfinfo.js
+++ b/lib/pdfinfo.js
@@ -1,6 +1,6 @@
 function pdfinfo (filename, options) {
   this.options = options || {};
-  this.options.additional = ['"' + filename + '"'];
+  this.options.additional = [filename];

   pdfinfo.prototype.add_options = function(optionArray) {
     if (typeof optionArray.length !== undefined) {
@@ -20,7 +20,7 @@
   pdfinfo.prototype.getInfoSync = function() {
     const self = this;
     try {
-    	let data = execSync('pdfinfo ' + self.options.additional.join(' ')).toString('utf8');
+    	let data = execFileSync('pdfinfo', self.options.additional).toString('utf8');
         return utils.parse(data);
     } catch(err) {
         throw new Error("pdfinfo error: "+ err.msg);
@@ -30,7 +30,7 @@

   pdfinfo.prototype.getInfo = function(cb) {
     let self = this;
-    let child = exec('pdfinfo ' + self.options.additional.join(' '), function(error, stdout, stderr) {
+    let child = execFile('pdfinfo', self.options.additional, (error, stdout, stderr) => {
       if (!error) {
         let data = utils.parse(stdout);
         if (cb && typeof cb === "function") {


A code injection issue was discovered in ipycache through 2016-05-31.

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.

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.

def load_vars(path, vars):
    """Load variables from a pickle file.

    Arguments:

      * path: the path to the pickle file.
      * vars: a list of variable names.

    Returns:

      * cache: a dictionary {var_name: var_value}.

    """
    with open(path, 'rb') as f:
        # Load the variables from the cache.
        try:
            cache = pickle.load(f)
        except EOFError as e:
            cache={}
            #raise IOError(str(e))

        # Check that all requested variables could be loaded successfully
        # from the cache.
        missing_vars = sorted(set(vars) - set(cache.keys()))
        if missing_vars:
            raise ValueError(("The following variables could not be loaded "
                "from the cache: {0:s}").format(
                ', '.join(["'{0:s}'".format(var) for var in missing_vars])))
        additional_vars = sorted(set(cache.keys()) - set(vars))
        for hidden_variable in '_captured_io', '_cell_md5':
            try:
                additional_vars.remove(hidden_variable)
            except ValueError:
                pass
        if additional_vars:
            raise ValueError("The following variables were present in the cache, "
                    "but removed from the storage request: {0:s}".format(
                ', '.join(["'{0:s}'".format(var) for var in additional_vars])))

        return cache

def load_vars(path, vars):
    """Load variables from a pickle file.

    Arguments:

      * path: the path to the pickle file.
      * vars: a list of variable names.

    Returns:

      * cache: a dictionary {var_name: var_value}.

    """
    with open(path, 'rb') as f:
        # Load the variables from the cache.
        try:
            restricted_loads(f.read())
            cache = pickle.load(f)
        except EOFError as e:
            cache={}
            #raise IOError(str(e))

        # Check that all requested variables could be loaded successfully
        # from the cache.
        missing_vars = sorted(set(vars) - set(cache.keys()))
        if missing_vars:
            raise ValueError(("The following variables could not be loaded "
                "from the cache: {0:s}").format(
                ', '.join(["'{0:s}'".format(var) for var in missing_vars])))
        additional_vars = sorted(set(cache.keys()) - set(vars))
        for hidden_variable in '_captured_io', '_cell_md5':
            try:
                additional_vars.remove(hidden_variable)
            except ValueError:
                pass
        if additional_vars:
            raise ValueError("The following variables were present in the cache, "
                    "but removed from the storage request: {0:s}".format(
                ', '.join(["'{0:s}'".format(var) for var in additional_vars])))

        return cache

class RestrictedUnpickler(pickle.Unpickler):

    def find_class(self, module, name):
        if module == '_io' and name == 'StringIO':
            return getattr(sys.modules[module], name)
        # Forbid everything else.
        raise pickle.UnpicklingError("global '%s.%s' is forbidden" %
                                     (module, name))

def restricted_loads(s):
    """Helper function analogous to pickle.loads()."""
    return RestrictedUnpickler(io.BytesIO(s)).load()

--- a/ipycache.py
+++ b/ipycache.py
@@ -14,6 +14,7 @@
     with open(path, 'rb') as f:
         # Load the variables from the cache.
         try:
+            restricted_loads(f.read())
             cache = pickle.load(f)
         except EOFError as e:
             cache={}

--- /dev/null
+++ b/ipycache.py
@@ -0,0 +1,13 @@
+class RestrictedUnpickler(pickle.Unpickler):
+
+    def find_class(self, module, name):
+        if module == '_io' and name == 'StringIO':
+            return getattr(sys.modules[module], name)
+        # Forbid everything else.
+        raise pickle.UnpicklingError("global '%s.%s' is forbidden" %
+                                     (module, name))
+
+
+def restricted_loads(s):
+    """Helper function analogous to pickle.loads()."""
+    return RestrictedUnpickler(io.BytesIO(s)).load()

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

cd /workspace/ipycache
git apply --whitespace=nowarn /workspace/test.patch /workspace/fix.patch
/workspace/PoC_env/CVE-2019-7539/bin/python -m pytest test_ipycache.py -v -k "test_load_exploitPickle"  -p no:warning --disable-warnings

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

cd /workspace/ipycache
git apply --whitespace=nowarn /workspace/fix.patch
/workspace/PoC_env/CVE-2019-7539/bin/python -m pytest test_ipycache.py -v -k "(test_conditional_eval) or (test_clean_var) or (test_clean_vars) or (test_do_save) or (test_load_fail) or (test_cache_outputs) or (test_cache_fail_1)" -p no:warning --disable-warnings


Authorization Bypass Through User-Controlled Key in GitHub repository emicklei/go-restful prior to v3.8.0.

Missing Authorization

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

The system's authorization functionality does not prevent one user from gaining access to another user's data or record by modifying the key value identifying the data.

func (c CrossOriginResourceSharing) isOriginAllowed(origin string) bool {
	if len(origin) == 0 {
		return false
	}
	if len(c.AllowedDomains) == 0 {
		return true
	}

	allowed := false
	for _, domain := range c.AllowedDomains {
		if domain == origin {
			allowed = true
			break
		}
	}

	if !allowed {
		if len(c.allowedOriginPatterns) == 0 {
			// compile allowed domains to allowed origin patterns
			allowedOriginRegexps, err := compileRegexps(c.AllowedDomains)
			if err != nil {
				return false
			}
			c.allowedOriginPatterns = allowedOriginRegexps
		}

		for _, pattern := range c.allowedOriginPatterns {
			if allowed = pattern.MatchString(origin); allowed {
				break
			}
		}
	}

	return allowed
}

func (c CrossOriginResourceSharing) isOriginAllowed(origin string) bool {
	if len(origin) == 0 {
		return false
	}
	lowerOrigin := strings.ToLower(origin)
	if len(c.AllowedDomains) == 0 {
		if c.AllowedDomainFunc != nil {
			return c.AllowedDomainFunc(lowerOrigin)
		}
		return true
	}

	// exact match on each allowed domain
	for _, domain := range c.AllowedDomains {
		if domain == ".*" || strings.ToLower(domain) == lowerOrigin {
			return true
		}
	}
	if c.AllowedDomainFunc != nil {
		return c.AllowedDomainFunc(origin)
	}
	return false
}

--- a/cors_filter.go
+++ b/cors_filter.go
@@ -2,34 +2,22 @@
 	if len(origin) == 0 {
 		return false
 	}
+	lowerOrigin := strings.ToLower(origin)
 	if len(c.AllowedDomains) == 0 {
+		if c.AllowedDomainFunc != nil {
+			return c.AllowedDomainFunc(lowerOrigin)
+		}
 		return true
 	}

-	allowed := false
+	// exact match on each allowed domain
 	for _, domain := range c.AllowedDomains {
-		if domain == origin {
-			allowed = true
-			break
+		if domain == ".*" || strings.ToLower(domain) == lowerOrigin {
+			return true
 		}
 	}
-
-	if !allowed {
-		if len(c.allowedOriginPatterns) == 0 {
-			// compile allowed domains to allowed origin patterns
-			allowedOriginRegexps, err := compileRegexps(c.AllowedDomains)
-			if err != nil {
-				return false
-			}
-			c.allowedOriginPatterns = allowedOriginRegexps
-		}
-
-		for _, pattern := range c.allowedOriginPatterns {
-			if allowed = pattern.MatchString(origin); allowed {
-				break
-			}
-		}
+	if c.AllowedDomainFunc != nil {
+		return c.AllowedDomainFunc(origin)
 	}
-
-	return allowed
+	return false
 }


A remote code execution vulnerability exists in mintplex-labs/anything-llm due to improper handling of environment variables. Attackers can exploit this vulnerability by injecting arbitrary environment variables via the `POST /api/system/update-env` endpoint, which allows for the execution of arbitrary code on the host running anything-llm. The vulnerability is present in the latest version of anything-llm, with the latest commit identified as fde905aac1812b84066ff72e5f2f90b56d4c3a59. This issue has been fixed in version 1.0.0. Successful exploitation could lead to code execution on the host, enabling attackers to read and modify data accessible to the user running the service, potentially leading to a denial of service.

async function dumpENV() {
  const fs = require("fs");
  const path = require("path");

  const frozenEnvs = {};
  const protectedKeys = [
    ...Object.values(KEY_MAPPING).map((values) => values.envKey),
    "STORAGE_DIR",
    "SERVER_PORT",
    // Password Schema Keys if present.
    "PASSWORDMINCHAR",
    "PASSWORDMAXCHAR",
    "PASSWORDLOWERCASE",
    "PASSWORDUPPERCASE",
    "PASSWORDNUMERIC",
    "PASSWORDSYMBOL",
    "PASSWORDREQUIREMENTS",
    // HTTPS SETUP KEYS
    "ENABLE_HTTPS",
    "HTTPS_CERT_PATH",
    "HTTPS_KEY_PATH",
    // DISABLED TELEMETRY
    "DISABLE_TELEMETRY",
  ];

  for (const key of protectedKeys) {
    const envValue = process.env?.[key] || null;
    if (!envValue) continue;
    frozenEnvs[key] = process.env?.[key] || null;
  }

  var envResult = `# Auto-dump ENV from system call on ${new Date().toTimeString()}\n`;
  envResult += Object.entries(frozenEnvs)
    .map(([key, value]) => {
      return `${key}='${value}'`;
    })
    .join("\n");

  const envPath = path.join(__dirname, "../../.env");
  fs.writeFileSync(envPath, envResult, { encoding: "utf8", flag: "w" });
  return true;
}

async function dumpENV() {
  const fs = require("fs");
  const path = require("path");

  const frozenEnvs = {};
  const protectedKeys = [
    ...Object.values(KEY_MAPPING).map((values) => values.envKey),
    "STORAGE_DIR",
    "SERVER_PORT",
    // Password Schema Keys if present.
    "PASSWORDMINCHAR",
    "PASSWORDMAXCHAR",
    "PASSWORDLOWERCASE",
    "PASSWORDUPPERCASE",
    "PASSWORDNUMERIC",
    "PASSWORDSYMBOL",
    "PASSWORDREQUIREMENTS",
    // HTTPS SETUP KEYS
    "ENABLE_HTTPS",
    "HTTPS_CERT_PATH",
    "HTTPS_KEY_PATH",
    // DISABLED TELEMETRY
    "DISABLE_TELEMETRY",
  ];

  // Simple sanitization of each value to prevent ENV injection via newline or quote escaping.
  function sanitizeValue(value) {
    const offendingChars =
      /[\n\r\t\v\f\u0085\u00a0\u1680\u180e\u2000-\u200a\u2028\u2029\u202f\u205f\u3000"'`#]/;
    const firstOffendingCharIndex = value.search(offendingChars);
    if (firstOffendingCharIndex === -1) return value;

    return value.substring(0, firstOffendingCharIndex);
  }

  for (const key of protectedKeys) {
    const envValue = process.env?.[key] || null;
    if (!envValue) continue;
    frozenEnvs[key] = process.env?.[key] || null;
  }

  var envResult = `# Auto-dump ENV from system call on ${new Date().toTimeString()}\n`;
  envResult += Object.entries(frozenEnvs)
    .map(([key, value]) => `${key}='${sanitizeValue(value)}'`)
    .join("\n");

  const envPath = path.join(__dirname, "../../.env");
  fs.writeFileSync(envPath, envResult, { encoding: "utf8", flag: "w" });
  return true;
}

--- a/server/utils/helpers/updateENV.js
+++ b/server/utils/helpers/updateENV.js
@@ -23,6 +23,16 @@
     "DISABLE_TELEMETRY",
   ];

+  // Simple sanitization of each value to prevent ENV injection via newline or quote escaping.
+  function sanitizeValue(value) {
+    const offendingChars =
+      /[\n\r\t\v\f\u0085\u00a0\u1680\u180e\u2000-\u200a\u2028\u2029\u202f\u205f\u3000"'`#]/;
+    const firstOffendingCharIndex = value.search(offendingChars);
+    if (firstOffendingCharIndex === -1) return value;
+
+    return value.substring(0, firstOffendingCharIndex);
+  }
+
   for (const key of protectedKeys) {
     const envValue = process.env?.[key] || null;
     if (!envValue) continue;
@@ -31,9 +41,7 @@

   var envResult = `# Auto-dump ENV from system call on ${new Date().toTimeString()}\n`;
   envResult += Object.entries(frozenEnvs)
-    .map(([key, value]) => {
-      return `${key}='${value}'`;
-    })
+    .map(([key, value]) => `${key}='${sanitizeValue(value)}'`)
     .join("\n");

   const envPath = path.join(__dirname, "../../.env");


Parse Server is an open source backend that can be deployed to any infrastructure that can run Node.js. It is an npm package "parse-server". In Parse Server before version 4.5.0, user passwords involved in LDAP authentication are stored in cleartext. This is fixed in version 4.5.0 by stripping password after authentication to prevent cleartext password storage.

Cleartext Storage of Sensitive Information

The product stores sensitive information in cleartext within a resource that might be accessible to another control sphere.

function validateAuthData(authData, options) {
  if (!optionsAreValid(options)) {
    return new Promise((_, reject) => {
      reject(
        new Parse.Error(
          Parse.Error.INTERNAL_SERVER_ERROR,
          'LDAP auth configuration missing'
        )
      );
    });
  }
  const clientOptions = (options.url.startsWith("ldaps://")) ?
    { url: options.url, tlsOptions: options.tlsOptions } : { url: options.url };

  const client = ldapjs.createClient(clientOptions);
  const userCn =
    typeof options.dn === 'string'
      ? options.dn.replace('{{id}}', authData.id)
      : `uid=${authData.id},${options.suffix}`;

  return new Promise((resolve, reject) => {
    client.bind(userCn, authData.password, ldapError => {
      if (ldapError) {
        let error;
        switch (ldapError.code) {
          case 49:
            error = new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'LDAP: Wrong username or password');
            break;
          case "DEPTH_ZERO_SELF_SIGNED_CERT":
            error = new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'LDAPS: Certificate mismatch');
            break;
          default:
            error = new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'LDAP: Somthing went wrong (' + ldapError.code + ')');
        }
        reject(error);
        client.destroy(ldapError);
        return;
      }

      if (
        typeof options.groupCn === 'string' &&
        typeof options.groupFilter === 'string'
      ) {
        searchForGroup(client, options, authData.id, resolve, reject);
      } else {
        client.unbind();
        client.destroy();
        resolve();
      }
    });
  });
}

function validateAuthData(authData, options) {
  if (!optionsAreValid(options)) {
    return new Promise((_, reject) => {
      reject(
        new Parse.Error(
          Parse.Error.INTERNAL_SERVER_ERROR,
          'LDAP auth configuration missing'
        )
      );
    });
  }
  const clientOptions = (options.url.startsWith("ldaps://")) ?
    { url: options.url, tlsOptions: options.tlsOptions } : { url: options.url };

  const client = ldapjs.createClient(clientOptions);
  const userCn =
    typeof options.dn === 'string'
      ? options.dn.replace('{{id}}', authData.id)
      : `uid=${authData.id},${options.suffix}`;

  return new Promise((resolve, reject) => {
    client.bind(userCn, authData.password, ldapError => {
      delete(authData.password);
      if (ldapError) {
        let error;
        switch (ldapError.code) {
          case 49:
            error = new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'LDAP: Wrong username or password');
            break;
          case "DEPTH_ZERO_SELF_SIGNED_CERT":
            error = new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'LDAPS: Certificate mismatch');
            break;
          default:
            error = new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'LDAP: Somthing went wrong (' + ldapError.code + ')');
        }
        reject(error);
        client.destroy(ldapError);
        return;
      }

      if (
        typeof options.groupCn === 'string' &&
        typeof options.groupFilter === 'string'
      ) {
        searchForGroup(client, options, authData.id, resolve, reject);
      } else {
        client.unbind();
        client.destroy();
        resolve();
      }
    });
  });
}

--- a/src/Adapters/Auth/ldap.js
+++ b/src/Adapters/Auth/ldap.js
@@ -20,6 +20,7 @@

   return new Promise((resolve, reject) => {
     client.bind(userCn, authData.password, ldapError => {
+      delete(authData.password);
       if (ldapError) {
         let error;
         switch (ldapError.code) {


An issue was discovered in Django 5.0 before 5.0.8 and 4.2 before 4.2.15. QuerySet.values() and values_list() methods on models with a JSONField are subject to SQL injection in column aliases via a crafted JSON object key as a passed *arg.

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

The product constructs all or part of an SQL command using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the intended SQL command when it is sent to a downstream component. Without sufficient removal or quoting of SQL syntax in user-controllable inputs, the generated SQL query can cause those inputs to be interpreted as SQL instead of ordinary user data.

    def set_values(self, fields):
        self.select_related = False
        self.clear_deferred_loading()
        self.clear_select_fields()
        self.has_select_fields = True

        if fields:
            field_names = []
            extra_names = []
            annotation_names = []
            if not self.extra and not self.annotations:
                # Shortcut - if there are no extra or annotations, then
                # the values() clause must be just field names.
                field_names = list(fields)
            else:
                self.default_cols = False
                for f in fields:
                    if f in self.extra_select:
                        extra_names.append(f)
                    elif f in self.annotation_select:
                        annotation_names.append(f)
                    elif f in self.annotations:
                        raise FieldError(
                            f"Cannot select the '{f}' alias. Use annotate() to "
                            "promote it."
                        )
                    else:
                        # Call `names_to_path` to ensure a FieldError including
                        # annotations about to be masked as valid choices if
                        # `f` is not resolvable.
                        if self.annotation_select:
                            self.names_to_path(f.split(LOOKUP_SEP), self.model._meta)
                        field_names.append(f)
            self.set_extra_mask(extra_names)
            self.set_annotation_mask(annotation_names)
            selected = frozenset(field_names + extra_names + annotation_names)
        else:
            field_names = [f.attname for f in self.model._meta.concrete_fields]
            selected = frozenset(field_names)
        # Selected annotations must be known before setting the GROUP BY
        # clause.
        if self.group_by is True:
            self.add_fields(
                (f.attname for f in self.model._meta.concrete_fields), False
            )
            # Disable GROUP BY aliases to avoid orphaning references to the
            # SELECT clause which is about to be cleared.
            self.set_group_by(allow_aliases=False)
            self.clear_select_fields()
        elif self.group_by:
            # Resolve GROUP BY annotation references if they are not part of
            # the selected fields anymore.
            group_by = []
            for expr in self.group_by:
                if isinstance(expr, Ref) and expr.refs not in selected:
                    expr = self.annotations[expr.refs]
                group_by.append(expr)
            self.group_by = tuple(group_by)

        self.values_select = tuple(field_names)
        self.add_fields(field_names, True)

    def set_values(self, fields):
        self.select_related = False
        self.clear_deferred_loading()
        self.clear_select_fields()
        self.has_select_fields = True

        if fields:
            for field in fields:
                self.check_alias(field)
            field_names = []
            extra_names = []
            annotation_names = []
            if not self.extra and not self.annotations:
                # Shortcut - if there are no extra or annotations, then
                # the values() clause must be just field names.
                field_names = list(fields)
            else:
                self.default_cols = False
                for f in fields:
                    if f in self.extra_select:
                        extra_names.append(f)
                    elif f in self.annotation_select:
                        annotation_names.append(f)
                    elif f in self.annotations:
                        raise FieldError(
                            f"Cannot select the '{f}' alias. Use annotate() to "
                            "promote it."
                        )
                    else:
                        # Call `names_to_path` to ensure a FieldError including
                        # annotations about to be masked as valid choices if
                        # `f` is not resolvable.
                        if self.annotation_select:
                            self.names_to_path(f.split(LOOKUP_SEP), self.model._meta)
                        field_names.append(f)
            self.set_extra_mask(extra_names)
            self.set_annotation_mask(annotation_names)
            selected = frozenset(field_names + extra_names + annotation_names)
        else:
            field_names = [f.attname for f in self.model._meta.concrete_fields]
            selected = frozenset(field_names)
        # Selected annotations must be known before setting the GROUP BY
        # clause.
        if self.group_by is True:
            self.add_fields(
                (f.attname for f in self.model._meta.concrete_fields), False
            )
            # Disable GROUP BY aliases to avoid orphaning references to the
            # SELECT clause which is about to be cleared.
            self.set_group_by(allow_aliases=False)
            self.clear_select_fields()
        elif self.group_by:
            # Resolve GROUP BY annotation references if they are not part of
            # the selected fields anymore.
            group_by = []
            for expr in self.group_by:
                if isinstance(expr, Ref) and expr.refs not in selected:
                    expr = self.annotations[expr.refs]
                group_by.append(expr)
            self.group_by = tuple(group_by)

        self.values_select = tuple(field_names)
        self.add_fields(field_names, True)

--- a/django/db/models/sql/query.py
+++ b/django/db/models/sql/query.py
@@ -5,6 +5,8 @@
         self.has_select_fields = True

         if fields:
+            for field in fields:
+                self.check_alias(field)
             field_names = []
             extra_names = []
             annotation_names = []

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

cd /workspace/django
git apply --whitespace=nowarn /workspace/test.patch /workspace/fix.patch
cd tests && /workspace/PoC_env/CVE-2024-42005/bin/python ./runtests.py expressions.test_queryset_values.ValuesExpressionsTests.test_values_expression_alias_sql_injection_json_field

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

cd /workspace/django
git apply --whitespace=nowarn /workspace/fix.patch
cd tests && /workspace/PoC_env/CVE-2024-42005/bin/python ./runtests.py expressions


A vulnerability was found in tarojs taro up to 4.1.1. It has been declared as problematic. This vulnerability affects unknown code of the file taro/packages/css-to-react-native/src/index.js. The manipulation leads to inefficient regular expression complexity. The attack can be initiated remotely. Upgrading to version 4.1.2 is able to address this issue. The name of the patch is c2e321a8b6fc873427c466c69f41ed0b5e8814bf. It is recommended to upgrade the affected component.

Inefficient Regular Expression Complexity

The product uses a regular expression with an inefficient, possibly exponential worst-case computational complexity that consumes excessive CPU cycles.

const transformDecls = (styles, declarations, result, options = {}) => {
  for (const d in declarations) {
    const declaration = declarations[d]
    if (declaration.type !== 'declaration') continue

    const property = declaration.property
    let value = remToPx(declaration.value)

    const isLengthUnit = lengthRe.test(value)
    const isViewportUnit = viewportUnitRe.test(value)
    const isPercent = percentRe.test(value)
    const isUnsupportedUnit = unsupportedUnitRe.test(value)

    if (
      property === 'line-height' &&
      !isLengthUnit &&
      !isViewportUnit &&
      !isPercent &&
      !isUnsupportedUnit
    ) {
      // ignore invalid value avoid throw error cause app crash
      continue
    }

    if (!result.__viewportUnits && isViewportUnit) {
      result.__viewportUnits = true
    }
    // scalable option, when it is false, transform single value 'px' unit to 'PX'
    // do not be wrapped by scalePx2dp function
    if (
      typeof options.scalable === 'boolean' &&
      !options.scalable &&
      /(\d+)px/.test(value)
    ) {
      value = value.replace(/(\d+)px/g, '$1PX')
    }
    // expect value is legal so that remove !import
    if (/!import/i.test(value)) {
      value = value.replace(/!import/, '')
    }

    if (shorthandBorderProps.indexOf(property) > -1) {
      // transform single value shorthand border properties back to
      // shorthand form to support styling `Image`.
      const transformed = transformCSS([[property, value]])
      const vals = values(transformed)
      if (allEqual(vals)) {
        const replacement = {}
        replacement[camelCase(property)] = vals[0]
        Object.assign(styles, replacement)
      } else {
        Object.assign(styles, transformed)
      }
    } else {
      Object.assign(styles, transformCSS([[property, value]]))
    }
  }
}

const transformDecls = (styles, declarations, result, options = {}) => {
  for (const d in declarations) {
    const declaration = declarations[d]
    if (declaration.type !== 'declaration') continue

    const property = declaration.property
    let value = remToPx(declaration.value)

    const isLengthUnit = lengthRe.test(value)
    const isViewportUnit = viewportUnitRe.test(value)
    const isPercent = percentRe.test(value)
    const isUnsupportedUnit = unsupportedUnitRe.test(value)

    if (
      property === 'line-height' &&
      !isLengthUnit &&
      !isViewportUnit &&
      !isPercent &&
      !isUnsupportedUnit
    ) {
      // ignore invalid value avoid throw error cause app crash
      continue
    }

    if (!result.__viewportUnits && isViewportUnit) {
      result.__viewportUnits = true
    }
    // scalable option, when it is false, transform single value 'px' unit to 'PX'
    // do not be wrapped by scalePx2dp function
    if (
      typeof options.scalable === 'boolean' &&
      !options.scalable &&
      /(?<!\d)(\d+)px/.test(value)
    ) {
      value = value.replace(/(?<!\d)(\d+)px/g, '$1PX')
    }
    // expect value is legal so that remove !import
    if (/!import/i.test(value)) {
      value = value.replace(/!import/, '')
    }

    if (shorthandBorderProps.indexOf(property) > -1) {
      // transform single value shorthand border properties back to
      // shorthand form to support styling `Image`.
      const transformed = transformCSS([[property, value]])
      const vals = values(transformed)
      if (allEqual(vals)) {
        const replacement = {}
        replacement[camelCase(property)] = vals[0]
        Object.assign(styles, replacement)
      } else {
        Object.assign(styles, transformed)
      }
    } else {
      Object.assign(styles, transformCSS([[property, value]]))
    }
  }
}

export const remToPx = value => {
  return value.replace(/(?<!\d)((?:\d*\.\d+)|\d+)rem/g, (match, m1) => parseFloat(m1, 10) * 16 + 'px')
}

--- a/packages/css-to-react-native/src/index.js
+++ b/packages/css-to-react-native/src/index.js
@@ -30,9 +30,9 @@
     if (
       typeof options.scalable === 'boolean' &&
       !options.scalable &&
-      /(\d+)px/.test(value)
+      /(?<!\d)(\d+)px/.test(value)
     ) {
-      value = value.replace(/(\d+)px/g, '$1PX')
+      value = value.replace(/(?<!\d)(\d+)px/g, '$1PX')
     }
     // expect value is legal so that remove !import
     if (/!import/i.test(value)) {

--- /dev/null
+++ b/packages/css-to-react-native/src/index.js
@@ -0,0 +1,3 @@
+export const remToPx = value => {
+  return value.replace(/(?<!\d)((?:\d*\.\d+)|\d+)rem/g, (match, m1) => parseFloat(m1, 10) * 16 + 'px')
+}


Plenti, a static site generator, has an arbitrary file deletion vulnerability in versions prior to 0.7.2. The `/postLocal` endpoint is vulnerable to an arbitrary file write deletion when a plenti user serves their website. This issue may lead to information loss. Version 0.7.2 fixes the vulnerability.

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 postLocal(w http.ResponseWriter, r *http.Request) {
	if r.Method == "POST" {
		b, err := ioutil.ReadAll(r.Body)
		if err != nil {
			fmt.Printf("Could not read 'body' from local edit: %v", err)
		}
		var localChanges []localChange
		err = json.Unmarshal(b, &localChanges)
		if err != nil {
			fmt.Printf("Could not unmarshal JSON data: %v", err)
		}
		var contents []byte
		for _, change := range localChanges {
			if change.Action == "create" || change.Action == "update" {
				contents = []byte(change.Contents)
				if change.Encoding == "base64" {
					contents, err = base64.StdEncoding.DecodeString(change.Contents)
					if err != nil {
						fmt.Printf("Could not decode base64 asset: %v", err)
					}
				}
				if len(change.File) > 0 && change.File[0:1] == "/" {
					// Make sure path is relative to project
					change.File = "." + change.File
				}
				err = os.WriteFile(change.File, contents, os.ModePerm)
				if err != nil {
					fmt.Printf("Unable to write to local file: %v", err)
				}
			}
			if change.Action == "delete" {
				currentDir, _ := os.Getwd()
				err = os.Remove(filepath.Join(currentDir, change.File))
				if err != nil {
					fmt.Printf("Unable to delete local file: %v", err)
				}
			}
		}
	}
}

func postLocal(w http.ResponseWriter, r *http.Request) {
	if r.Method == "POST" {
		b, err := ioutil.ReadAll(r.Body)
		if err != nil {
			fmt.Printf("Could not read 'body' from local edit: %v", err)
		}
		var localChanges []localChange
		err = json.Unmarshal(b, &localChanges)
		if err != nil {
			fmt.Printf("Could not unmarshal JSON data: %v", err)
		}
		var contents []byte
		currentDir, _ := os.Getwd()
		for _, change := range localChanges {
			change.File = filepath.Join(currentDir, filepath.Clean("/"+change.File))

			if change.Action == "create" || change.Action == "update" {
				contents = []byte(change.Contents)
				if change.Encoding == "base64" {
					contents, err = base64.StdEncoding.DecodeString(change.Contents)
					if err != nil {
						fmt.Printf("Could not decode base64 asset: %v", err)
					}
				}
				err = os.WriteFile(change.File, contents, os.ModePerm)
				if err != nil {
					fmt.Printf("Unable to write to local file: %v", err)
				}
			}

			if change.Action == "delete" {
				err = os.Remove(change.File)
				if err != nil {
					fmt.Printf("Unable to delete local file: %v", err)
				}
			}
		}
	}
}

--- a/cmd/serve.go
+++ b/cmd/serve.go
@@ -10,7 +10,10 @@
 			fmt.Printf("Could not unmarshal JSON data: %v", err)
 		}
 		var contents []byte
+		currentDir, _ := os.Getwd()
 		for _, change := range localChanges {
+			change.File = filepath.Join(currentDir, filepath.Clean("/"+change.File))
+
 			if change.Action == "create" || change.Action == "update" {
 				contents = []byte(change.Contents)
 				if change.Encoding == "base64" {
@@ -19,18 +22,14 @@
 						fmt.Printf("Could not decode base64 asset: %v", err)
 					}
 				}
-				if len(change.File) > 0 && change.File[0:1] == "/" {
-					// Make sure path is relative to project
-					change.File = "." + change.File
-				}
 				err = os.WriteFile(change.File, contents, os.ModePerm)
 				if err != nil {
 					fmt.Printf("Unable to write to local file: %v", err)
 				}
 			}
+
 			if change.Action == "delete" {
-				currentDir, _ := os.Getwd()
-				err = os.Remove(filepath.Join(currentDir, change.File))
+				err = os.Remove(change.File)
 				if err != nil {
 					fmt.Printf("Unable to delete local file: %v", err)
 				}


OpenCanary, a multi-protocol network honeypot, directly executed commands taken from its config file. Prior to version 0.9.4, where the config file is stored in an unprivileged user directory but the daemon is executed by root, it’s possible for the unprivileged user to change the config file and escalate permissions when root later runs the daemon. Version 0.9.4 contains a fix for the issue.

Incorrect Authorization

The product performs an authorization check when an actor attempts to access a resource or perform an action, but it does not correctly perform the check.

    def __init__(self, configfile=SETTINGS):
        self.__config = None
        self.__configfile = configfile

        files = [
            configfile,
            "%s/.%s" % (expanduser("~"), configfile),
            "/etc/opencanaryd/%s" % configfile,
        ]
        print(
            "** We hope you enjoy using OpenCanary. For more open source Canary goodness, head over to canarytokens.org. **"
        )
        for fname in files:
            try:
                with open(fname, "r") as f:
                    print("[-] Using config file: %s" % fname)
                    self.__config = json.load(f)
                    self.__config = expand_vars(self.__config)
                return
            except IOError as e:
                print("[-] Failed to open %s for reading (%s)" % (fname, e))
            except ValueError as e:
                print("[-] Failed to decode json from %s (%s)" % (fname, e))
                subprocess.call(
                    "cp -r %s /var/tmp/config-err-$(date +%%s)" % fname, shell=True
                )
            except Exception as e:
                print("[-] An error occurred loading %s (%s)" % (fname, e))
        if self.__config is None:
            print(
                'No config file found. Please create one with "opencanaryd --copyconfig"'
            )
            sys.exit(1)

def detectNFTables():
    return b"nf_tables" in subprocess.check_output(["iptables", "--version"])

    def __init__(self, configfile=SETTINGS):
        self.__config = None
        self.__configfile = configfile

        files = [
            "/etc/opencanaryd/%s" % configfile,
            "%s/.%s" % (expanduser("~"), configfile),
            configfile,
        ]
        print(
            "** We hope you enjoy using OpenCanary. For more open source Canary goodness, head over to canarytokens.org. **"
        )
        for fname in files:
            try:
                with open(fname, "r") as f:
                    print("[-] Using config file: %s" % fname)
                    self.__config = json.load(f)
                    self.__config = expand_vars(self.__config)
                if fname is configfile:
                    print(
                        "[-] Warning, making use of the configuration file in the immediate directory is not recommended! Suggested locations: %s"
                        % ", ".join(files[:2])
                    )
                return
            except IOError as e:
                print("[-] Failed to open %s for reading (%s)" % (fname, e))
            except ValueError as e:
                print("[-] Failed to decode json from %s (%s)" % (fname, e))
                safe_exec("cp", ["-r", fname, "/var/tmp/config-err-$(date +%%s)"])
            except Exception as e:
                print("[-] An error occurred loading %s (%s)" % (fname, e))
        if self.__config is None:
            print(
                'No config file found. Please create one with "opencanaryd --copyconfig"'
            )
            sys.exit(1)

def detectNFTables():
    return b"nf_tables" in safe_exec("iptables", ["--version"])

--- a/opencanary/config.py
+++ b/opencanary/config.py
@@ -3,9 +3,9 @@
         self.__configfile = configfile

         files = [
+            "/etc/opencanaryd/%s" % configfile,
+            "%s/.%s" % (expanduser("~"), configfile),
             configfile,
-            "%s/.%s" % (expanduser("~"), configfile),
-            "/etc/opencanaryd/%s" % configfile,
         ]
         print(
             "** We hope you enjoy using OpenCanary. For more open source Canary goodness, head over to canarytokens.org. **"
@@ -16,14 +16,17 @@
                     print("[-] Using config file: %s" % fname)
                     self.__config = json.load(f)
                     self.__config = expand_vars(self.__config)
+                if fname is configfile:
+                    print(
+                        "[-] Warning, making use of the configuration file in the immediate directory is not recommended! Suggested locations: %s"
+                        % ", ".join(files[:2])
+                    )
                 return
             except IOError as e:
                 print("[-] Failed to open %s for reading (%s)" % (fname, e))
             except ValueError as e:
                 print("[-] Failed to decode json from %s (%s)" % (fname, e))
-                subprocess.call(
-                    "cp -r %s /var/tmp/config-err-$(date +%%s)" % fname, shell=True
-                )
+                safe_exec("cp", ["-r", fname, "/var/tmp/config-err-$(date +%%s)"])
             except Exception as e:
                 print("[-] An error occurred loading %s (%s)" % (fname, e))
         if self.__config is None:

--- a/opencanary/modules/portscan.py
+++ b/opencanary/modules/portscan.py
@@ -1,2 +1,2 @@
 def detectNFTables():
-    return b"nf_tables" in subprocess.check_output(["iptables", "--version"])
+    return b"nf_tables" in safe_exec("iptables", ["--version"])

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

cd /workspace/opencanary
git apply --whitespace=nowarn /workspace/test.patch /workspace/fix.patch
/workspace/PoC_env/CVE-2024-48911/bin/python  hand_test.py


Path Traversal in GitHub repository mlflow/mlflow prior to 2.9.2.

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.

    def load(self, dst_path=None) -> str:
        """
        Downloads the dataset source to the local filesystem.

        :param dst_path: Path of the local filesystem destination directory to which to download the
                         dataset source. If the directory does not exist, it is created. If
                         unspecified, the dataset source is downloaded to a new uniquely-named
                         directory on the local filesystem.
        :return: The path to the downloaded dataset source on the local filesystem.
        """
        resp = cloud_storage_http_request(
            method="GET",
            url=self.url,
            stream=True,
        )
        augmented_raise_for_status(resp)

        path = urlparse(self.url).path
        content_disposition = resp.headers.get("Content-Disposition")
        if content_disposition is not None and (
            file_name := next(re.finditer(r"filename=(.+)", content_disposition), None)
        ):
            # NB: If the filename is quoted, unquote it
            basename = file_name[1].strip("'\"")
            if _is_path(basename):
                raise MlflowException.invalid_parameter_value(
                    f"Invalid filename in Content-Disposition header: {basename}. "
                    "It must be a file name, not a path."
                )
        elif path is not None and len(posixpath.basename(path)) > 0:
            basename = posixpath.basename(path)
        else:
            basename = "dataset_source"

        if dst_path is None:
            dst_path = create_tmp_dir()

        dst_path = os.path.join(dst_path, basename)
        with open(dst_path, "wb") as f:
            chunk_size = 1024 * 1024  # 1 MB
            for chunk in resp.iter_content(chunk_size=chunk_size):
                f.write(chunk)

        return dst_path

    def load(self, dst_path=None) -> str:
        """
        Downloads the dataset source to the local filesystem.

        :param dst_path: Path of the local filesystem destination directory to which to download the
                         dataset source. If the directory does not exist, it is created. If
                         unspecified, the dataset source is downloaded to a new uniquely-named
                         directory on the local filesystem.
        :return: The path to the downloaded dataset source on the local filesystem.
        """
        resp = cloud_storage_http_request(
            method="GET",
            url=self.url,
            stream=True,
        )
        augmented_raise_for_status(resp)

        basename = self._extract_filename(resp)

        if not basename:
            basename = "dataset_source"

        if dst_path is None:
            dst_path = create_tmp_dir()

        dst_path = os.path.join(dst_path, basename)
        with open(dst_path, "wb") as f:
            chunk_size = 1024 * 1024  # 1 MB
            for chunk in resp.iter_content(chunk_size=chunk_size):
                f.write(chunk)

        return dst_path

--- a/mlflow/data/http_dataset_source.py
+++ b/mlflow/data/http_dataset_source.py
@@ -15,21 +15,9 @@
         )
         augmented_raise_for_status(resp)

-        path = urlparse(self.url).path
-        content_disposition = resp.headers.get("Content-Disposition")
-        if content_disposition is not None and (
-            file_name := next(re.finditer(r"filename=(.+)", content_disposition), None)
-        ):
-            # NB: If the filename is quoted, unquote it
-            basename = file_name[1].strip("'\"")
-            if _is_path(basename):
-                raise MlflowException.invalid_parameter_value(
-                    f"Invalid filename in Content-Disposition header: {basename}. "
-                    "It must be a file name, not a path."
-                )
-        elif path is not None and len(posixpath.basename(path)) > 0:
-            basename = posixpath.basename(path)
-        else:
+        basename = self._extract_filename(resp)
+
+        if not basename:
             basename = "dataset_source"

         if dst_path is None:


dot-object before 2.1.3 is vulnerable to Prototype Pollution. The set function could be tricked into adding or modifying properties of Object.prototype using a __proto__ payload.

Improper Neutralization of Special Elements in Output Used by a Downstream Component ('Injection')

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

function parsePath (path, sep) {
  if (path.indexOf('[') >= 0) {
    path = path.replace(/\[/g, '.').replace(/]/g, '')
  }
  return path.split(sep)
}

const blacklist = ['__proto__', 'prototype', 'constructor']

function parsePath (path, sep) {
  if (path.indexOf('[') >= 0) {
    path = path.replace(/\[/g, '.').replace(/]/g, '')
  }

  const parts = path.split(sep)

  const check = parts.filter(part => blacklist.indexOf(part) === -1)

  if (check.length !== parts.length) {
    throw Error('Refusing to update blacklisted property ' + path)
  }

  return parts
}

--- a/index.js
+++ b/index.js
@@ -1,6 +1,17 @@
+const blacklist = ['__proto__', 'prototype', 'constructor']
+
 function parsePath (path, sep) {
   if (path.indexOf('[') >= 0) {
     path = path.replace(/\[/g, '.').replace(/]/g, '')
   }
-  return path.split(sep)
+
+  const parts = path.split(sep)
+
+  const check = parts.filter(part => blacklist.indexOf(part) === -1)
+
+  if (check.length !== parts.length) {
+    throw Error('Refusing to update blacklisted property ' + path)
+  }
+
+  return parts
 }

--- a/src/dot-object.js
+++ b/src/dot-object.js
@@ -1,6 +1,17 @@
+const blacklist = ['__proto__', 'prototype', 'constructor']
+
 function parsePath (path, sep) {
   if (path.indexOf('[') >= 0) {
     path = path.replace(/\[/g, '.').replace(/]/g, '')
   }
-  return path.split(sep)
+
+  const parts = path.split(sep)
+
+  const check = parts.filter(part => blacklist.indexOf(part) === -1)
+
+  if (check.length !== parts.length) {
+    throw Error('Refusing to update blacklisted property ' + path)
+  }
+
+  return parts
 }


SickChill is an automatic video library manager for TV shows. A user-controlled `login` endpoint's `next_` parameter takes arbitrary content. Prior to commit c7128a8946c3701df95c285810eb75b2de18bf82, an authenticated attacker may use this to redirect the user to arbitrary destinations, leading to open redirect. Commit c7128a8946c3701df95c285810eb75b2de18bf82 changes the login page to redirect to `settings.DEFAULT_PAGE` instead of to the `next` parameter.

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.

    def post(self, next_=None):
        notifiers.notify_login(self.request.remote_ip)
        global login_error

        if self.get_body_argument("username", None) == settings.WEB_USERNAME and self.get_body_argument("password", None) == settings.WEB_PASSWORD:
            login_error = ""
            remember_me = config.checkbox_to_value(self.get_body_argument("remember_me", "0"))
            self.set_secure_cookie("sickchill_user", settings.API_KEY, expires_days=(None, 30)[remember_me])
            logger.info(_("User logged into the SickChill web interface"))
        else:
            logger.warning(_("User attempted a failed login to the SickChill web interface from IP: ") + self.request.remote_ip)
            login_error = _("Incorrect username or password! Both username and password are case sensitive!")

        next_ = self.get_query_argument("next", next_)
        self.redirect(next_ or "/" + settings.DEFAULT_PAGE + "/")

    def post(self, next_=None):
        notifiers.notify_login(self.request.remote_ip)
        global login_error

        if self.get_body_argument("username", None) == settings.WEB_USERNAME and self.get_body_argument("password", None) == settings.WEB_PASSWORD:
            login_error = ""
            remember_me = config.checkbox_to_value(self.get_body_argument("remember_me", "0"))
            self.set_secure_cookie("sickchill_user", settings.API_KEY, expires_days=(None, 30)[remember_me])
            logger.info(_("User logged into the SickChill web interface"))
        else:
            logger.warning(_("User attempted a failed login to the SickChill web interface from IP: ") + self.request.remote_ip)
            login_error = _("Incorrect username or password! Both username and password are case sensitive!")

        self.redirect("/" + settings.DEFAULT_PAGE + "/")

--- a/sickchill/views/authentication.py
+++ b/sickchill/views/authentication.py
@@ -11,5 +11,4 @@
             logger.warning(_("User attempted a failed login to the SickChill web interface from IP: ") + self.request.remote_ip)
             login_error = _("Incorrect username or password! Both username and password are case sensitive!")

-        next_ = self.get_query_argument("next", next_)
-        self.redirect(next_ or "/" + settings.DEFAULT_PAGE + "/")
+        self.redirect("/" + settings.DEFAULT_PAGE + "/")


Computer Vision Annotation Tool (CVAT) is an interactive video and image annotation tool for computer vision. An attacker with a CVAT account can access webhook delivery information for any webhook registered on the CVAT instance, including that of other users. For each delivery, this contains information about the event that caused the delivery, typically including full details about the object on which an action was performed (such as the task for an "update:task" event), and the user who performed the action. In addition, the attacker can redeliver any past delivery of any webhook, and trigger a ping event for any webhook. Upgrade to CVAT 2.18.0 or any later version.

    def get_scopes(request, view, obj):
        Scopes = __class__.Scopes
        scope = {
            ('create', 'POST'): Scopes.CREATE,
            ('destroy', 'DELETE'): Scopes.DELETE,
            ('partial_update', 'PATCH'): Scopes.UPDATE,
            ('update', 'PUT'): Scopes.UPDATE,
            ('list', 'GET'): Scopes.LIST,
            ('retrieve', 'GET'): Scopes.VIEW,
        }.get((view.action, request.method))

        scopes = []
        if scope == Scopes.CREATE:
            webhook_type = request.data.get('type')
            if webhook_type in [m.value for m in WebhookTypeChoice]:
                scope = Scopes(str(scope) + f'@{webhook_type}')
            scopes.append(scope)
        elif scope in [Scopes.UPDATE, Scopes.DELETE, Scopes.LIST, Scopes.VIEW]:
            scopes.append(scope)

        return scopes

    def get_scopes(request, view, obj):
        Scopes = __class__.Scopes
        scope = {
            ('create', 'POST'): Scopes.CREATE,
            ('destroy', 'DELETE'): Scopes.DELETE,
            ('partial_update', 'PATCH'): Scopes.UPDATE,
            ('update', 'PUT'): Scopes.UPDATE,
            ('list', 'GET'): Scopes.LIST,
            ('retrieve', 'GET'): Scopes.VIEW,
            ('ping', 'POST'): Scopes.UPDATE,
            ('deliveries', 'GET'): Scopes.VIEW,
            ('retrieve_delivery', 'GET'): Scopes.VIEW,
            ('redelivery', 'POST'): Scopes.UPDATE,
        }.get((view.action, request.method))

        scopes = []
        if scope == Scopes.CREATE:
            webhook_type = request.data.get('type')
            if webhook_type in [m.value for m in WebhookTypeChoice]:
                scope = Scopes(str(scope) + f'@{webhook_type}')
            scopes.append(scope)
        elif scope in [Scopes.UPDATE, Scopes.DELETE, Scopes.LIST, Scopes.VIEW]:
            scopes.append(scope)

        return scopes

--- a/cvat/apps/webhooks/permissions.py
+++ b/cvat/apps/webhooks/permissions.py
@@ -7,6 +7,10 @@
             ('update', 'PUT'): Scopes.UPDATE,
             ('list', 'GET'): Scopes.LIST,
             ('retrieve', 'GET'): Scopes.VIEW,
+            ('ping', 'POST'): Scopes.UPDATE,
+            ('deliveries', 'GET'): Scopes.VIEW,
+            ('retrieve_delivery', 'GET'): Scopes.VIEW,
+            ('redelivery', 'POST'): Scopes.UPDATE,
         }.get((view.action, request.method))

         scopes = []


lunary-ai/lunary version 1.0.1 is vulnerable to improper authorization, allowing removed members to read, create, modify, and delete prompt templates using an old authorization token. Despite being removed from an organization, these members can still perform operations on prompt templates by sending HTTP requests with their previously captured authorization token. This issue exposes organizations to unauthorized access and manipulation of sensitive template data.

export async function authMiddleware(ctx: Context, next: Next) {
  ctx.state.projectId = ctx.request?.query?.projectId as string

  const isPublicRoute = publicRoutes.some((route) =>
    typeof route === "string" ? route === ctx.path : route.test(ctx.path),
  )

  const bearer = ctx.request?.headers?.authorization?.split(" ")[1] as string
  const apiKey = ctx.request?.headers?.["x-api-key"] as string

  const key = bearer || apiKey

  // For routes like signup, login, etc
  if (isPublicRoute && !key) {
    await next()
    return
  }
  // Check if API key is valid
  // Support passing as bearer because legacy SDKs did that
  else if (validateUUID(key)) {
    console.log("key", key)

    const { type, projectId, orgId } = await checkApiKey(ctx, key as string)
    console.log({ type, projectId, orgId })

    ctx.state.projectId = projectId
    ctx.state.orgId = orgId

    if (type === "public" && !isPublicRoute) {
      ctx.throw(401, "This route requires a private API key")
    }

    if (type == "private") {
      ctx.state.privateKey = true
    }
  } else {
    // Check if JWT is valid
    try {
      if (!bearer) {
        throw new Error("No bearer token provided.")
      }
      const { payload } = await verifyJwt<SessionData>(key)

      ctx.state.userId = payload.userId
      ctx.state.orgId = payload.orgId

      if (ctx.state.projectId) {
        // Check if user has access to project

        const [project] = await sql`
        select * from account_project where account_id = ${ctx.state.userId} and project_id = ${ctx.state.projectId}
      `

        if (!project) {
          throw new Error("Project not found")
        }
      }
    } catch (error) {
      console.error(error)
      ctx.throw(401, "Invalid access token")
    }
  }

  await next()
}

export async function authMiddleware(ctx: Context, next: Next) {
  ctx.state.projectId = ctx.request?.query?.projectId as string

  const isPublicRoute = publicRoutes.some((route) =>
    typeof route === "string" ? route === ctx.path : route.test(ctx.path),
  )

  const bearer = ctx.request?.headers?.authorization?.split(" ")[1] as string
  const apiKey = ctx.request?.headers?.["x-api-key"] as string

  const key = bearer || apiKey

  // For routes like signup, login, etc
  if (isPublicRoute && !key) {
    await next()
    return
  }
  // Check if API key is valid
  // Support passing as bearer because legacy SDKs did that
  else if (validateUUID(key)) {
    const { type, projectId, orgId } = await checkApiKey(ctx, key as string)

    ctx.state.projectId = projectId
    ctx.state.orgId = orgId

    if (type === "public" && !isPublicRoute) {
      ctx.throw(401, "This route requires a private API key")
    }

    if (type == "private") {
      ctx.state.privateKey = true
    }
  } else {
    // Check if JWT is valid
    try {
      if (!bearer) {
        throw new Error("No bearer token provided.")
      }
      const { payload } = await verifyJwt<SessionData>(key)

      ctx.state.userId = payload.userId
      ctx.state.orgId = payload.orgId

      const [user] =
        await sql`select * from account where id = ${ctx.state.userId}`
      if (!user) {
        ctx.throw(401, "This account no longer exists")
      }

      if (ctx.state.projectId) {
        // Check if user has access to project

        const [project] = await sql`
          select * from account_project where account_id = ${ctx.state.userId} and project_id = ${ctx.state.projectId}
        `

        if (!project) {
          throw new Error("Project not found")
        }
      }
    } catch (error) {
      console.error(error)
      ctx.throw(401, "Invalid access token")
    }
  }

  await next()
}

--- a/packages/backend/src/api/v1/auth/utils.ts
+++ b/packages/backend/src/api/v1/auth/utils.ts
@@ -18,10 +18,7 @@
   // Check if API key is valid
   // Support passing as bearer because legacy SDKs did that
   else if (validateUUID(key)) {
-    console.log("key", key)
-
     const { type, projectId, orgId } = await checkApiKey(ctx, key as string)
-    console.log({ type, projectId, orgId })

     ctx.state.projectId = projectId
     ctx.state.orgId = orgId
@@ -44,12 +41,18 @@
       ctx.state.userId = payload.userId
       ctx.state.orgId = payload.orgId

+      const [user] =
+        await sql`select * from account where id = ${ctx.state.userId}`
+      if (!user) {
+        ctx.throw(401, "This account no longer exists")
+      }
+
       if (ctx.state.projectId) {
         // Check if user has access to project

         const [project] = await sql`
-        select * from account_project where account_id = ${ctx.state.userId} and project_id = ${ctx.state.projectId}
-      `
+          select * from account_project where account_id = ${ctx.state.userId} and project_id = ${ctx.state.projectId}
+        `

         if (!project) {
           throw new Error("Project not found")


salt before 2015.5.5 leaks git usernames and passwords to the log.

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 _git_run(cmd, cwd=None, runas=None, identity=None, **kwargs):
    '''
    simple, throw an exception with the error message on an error return code.

    this function may be moved to the command module, spliced with
    'cmd.run_all', and used as an alternative to 'cmd.run_all'. Some
    commands don't return proper retcodes, so this can't replace 'cmd.run_all'.
    '''
    env = {}

    if identity:
        stderrs = []

        # if the statefile provides multiple identities, they need to be tried
        # (but also allow a string instead of a list)
        if not isinstance(identity, list):
            # force it into a list
            identity = [identity]

        # try each of the identities, independently
        for id_file in identity:
            env = {
                'GIT_IDENTITY': id_file
            }

            # copy wrapper to area accessible by ``runas`` user
            # currently no suppport in windows for wrapping git ssh
            if not utils.is_windows():
                ssh_id_wrapper = os.path.join(utils.templates.TEMPLATE_DIRNAME,
                                              'git/ssh-id-wrapper')
                tmp_file = utils.mkstemp()
                utils.files.copyfile(ssh_id_wrapper, tmp_file)
                os.chmod(tmp_file, 0o500)
                os.chown(tmp_file, __salt__['file.user_to_uid'](runas), -1)
                env['GIT_SSH'] = tmp_file

            try:
                result = __salt__['cmd.run_all'](cmd,
                                                 cwd=cwd,
                                                 runas=runas,
                                                 env=env,
                                                 python_shell=False,
                                                 **kwargs)
            finally:
                if 'GIT_SSH' in env:
                    os.remove(env['GIT_SSH'])

            # if the command was successful, no need to try additional IDs
            if result['retcode'] == 0:
                return result['stdout']
            else:
                stderrs.append(result['stderr'])

        # we've tried all IDs and still haven't passed, so error out
        raise CommandExecutionError("\n\n".join(stderrs))

    else:
        result = __salt__['cmd.run_all'](cmd,
                                         cwd=cwd,
                                         runas=runas,
                                         env=env,
                                         python_shell=False,
                                         **kwargs)
        retcode = result['retcode']

        if retcode == 0:
            return result['stdout']
        else:
            raise CommandExecutionError(
                'Command {0!r} failed. Stderr: {1!r}'.format(cmd,
                                                             result['stderr']))

def _git_run(cmd, cwd=None, runas=None, identity=None, **kwargs):
    '''
    simple, throw an exception with the error message on an error return code.

    this function may be moved to the command module, spliced with
    'cmd.run_all', and used as an alternative to 'cmd.run_all'. Some
    commands don't return proper retcodes, so this can't replace 'cmd.run_all'.
    '''
    env = {}

    if identity:
        stderrs = []

        # if the statefile provides multiple identities, they need to be tried
        # (but also allow a string instead of a list)
        if not isinstance(identity, list):
            # force it into a list
            identity = [identity]

        # try each of the identities, independently
        for id_file in identity:
            env = {
                'GIT_IDENTITY': id_file
            }

            # copy wrapper to area accessible by ``runas`` user
            # currently no suppport in windows for wrapping git ssh
            if not utils.is_windows():
                ssh_id_wrapper = os.path.join(utils.templates.TEMPLATE_DIRNAME,
                                              'git/ssh-id-wrapper')
                tmp_file = utils.mkstemp()
                utils.files.copyfile(ssh_id_wrapper, tmp_file)
                os.chmod(tmp_file, 0o500)
                os.chown(tmp_file, __salt__['file.user_to_uid'](runas), -1)
                env['GIT_SSH'] = tmp_file

            try:
                result = __salt__['cmd.run_all'](cmd,
                                                 cwd=cwd,
                                                 runas=runas,
                                                 output_loglevel='quiet',
                                                 env=env,
                                                 python_shell=False,
                                                 **kwargs)
            finally:
                if 'GIT_SSH' in env:
                    os.remove(env['GIT_SSH'])

            # if the command was successful, no need to try additional IDs
            if result['retcode'] == 0:
                return result['stdout']
            else:
                stderr = _remove_sensitive_data(result['stderr'])
                stderrs.append(stderr)

        # we've tried all IDs and still haven't passed, so error out
        raise CommandExecutionError("\n\n".join(stderrs))

    else:
        result = __salt__['cmd.run_all'](cmd,
                                         cwd=cwd,
                                         runas=runas,
                                         output_loglevel='quiet',
                                         env=env,
                                         python_shell=False,
                                         **kwargs)
        retcode = result['retcode']

        if retcode == 0:
            return result['stdout']
        else:
            stderr = _remove_sensitive_data(result['stderr'])
            raise CommandExecutionError(
                'Command {0!r} failed. Stderr: {1!r}'.format(cmd, stderr))

def _remove_sensitive_data(sensitive_output):
    '''
        Remove HTTP user and password.
    '''
    return re.sub('(https?)://.*@', r'\1://<redacted>@', sensitive_output)

--- a/salt/modules/git.py
+++ b/salt/modules/git.py
@@ -38,6 +38,7 @@
                 result = __salt__['cmd.run_all'](cmd,
                                                  cwd=cwd,
                                                  runas=runas,
+                                                 output_loglevel='quiet',
                                                  env=env,
                                                  python_shell=False,
                                                  **kwargs)
@@ -49,7 +50,8 @@
             if result['retcode'] == 0:
                 return result['stdout']
             else:
-                stderrs.append(result['stderr'])
+                stderr = _remove_sensitive_data(result['stderr'])
+                stderrs.append(stderr)

         # we've tried all IDs and still haven't passed, so error out
         raise CommandExecutionError("\n\n".join(stderrs))
@@ -58,6 +60,7 @@
         result = __salt__['cmd.run_all'](cmd,
                                          cwd=cwd,
                                          runas=runas,
+                                         output_loglevel='quiet',
                                          env=env,
                                          python_shell=False,
                                          **kwargs)
@@ -66,6 +69,6 @@
         if retcode == 0:
             return result['stdout']
         else:
+            stderr = _remove_sensitive_data(result['stderr'])
             raise CommandExecutionError(
-                'Command {0!r} failed. Stderr: {1!r}'.format(cmd,
-                                                             result['stderr']))
+                'Command {0!r} failed. Stderr: {1!r}'.format(cmd, stderr))

--- /dev/null
+++ b/salt/modules/git.py
@@ -0,0 +1,5 @@
+def _remove_sensitive_data(sensitive_output):
+    '''
+        Remove HTTP user and password.
+    '''
+    return re.sub('(https?)://.*@', r'\1://<redacted>@', sensitive_output)


A command injection vulnerability in egg-scripts <v2.8.1 allows arbitrary shell command execution through a maliciously crafted command line argument.

  * checkStatus({ stderr, timeout, 'ignore-stderr': ignoreStdErr }) {
    let count = 0;
    let hasError = false;
    let isSuccess = true;
    timeout = timeout / 1000;
    while (!this.isReady) {
      try {
        const stat = yield fs.stat(stderr);
        if (stat && stat.size > 0) {
          hasError = true;
          break;
        }
      } catch (_) {
        // nothing
      }

      if (count >= timeout) {
        this.logger.error('Start failed, %ds timeout', timeout);
        isSuccess = false;
        break;
      }

      yield sleep(1000);
      this.logger.log('Wait Start: %d...', ++count);
    }

    if (hasError) {
      try {
        const [ stdout ] = yield exec('tail -n 100 ' + stderr);
        this.logger.error('Got error when startup: ');
        this.logger.error(stdout);
      } catch (_) {
        // nothing
      }
      isSuccess = ignoreStdErr;
      this.logger.error('Start got error, see %s', stderr);
      this.logger.error('Or use `--ignore-stderr` to ignore stderr at startup.');
    }

    if (!isSuccess) {
      this.child.kill('SIGTERM');
      yield sleep(1000);
      this.exit(1);
    }
  }

  * checkStatus({ stderr, timeout, 'ignore-stderr': ignoreStdErr }) {
    let count = 0;
    let hasError = false;
    let isSuccess = true;
    timeout = timeout / 1000;
    while (!this.isReady) {
      try {
        const stat = yield fs.stat(stderr);
        if (stat && stat.size > 0) {
          hasError = true;
          break;
        }
      } catch (_) {
        // nothing
      }

      if (count >= timeout) {
        this.logger.error('Start failed, %ds timeout', timeout);
        isSuccess = false;
        break;
      }

      yield sleep(1000);
      this.logger.log('Wait Start: %d...', ++count);
    }

    if (hasError) {
      try {
        const args = [ '-n', '100', stderr ];
        this.logger.error('tail %s', args.join(' '));
        const [ stdout ] = yield execFile('tail', args);
        this.logger.error('Got error when startup: ');
        this.logger.error(stdout);
      } catch (err) {
        this.logger.error('ignore tail error: %s', err);
      }

      isSuccess = ignoreStdErr;
      this.logger.error('Start got error, see %s', stderr);
      this.logger.error('Or use `--ignore-stderr` to ignore stderr at startup.');
    }

    if (!isSuccess) {
      this.child.kill('SIGTERM');
      yield sleep(1000);
      this.exit(1);
    }
  }

--- a/lib/cmd/start.js
+++ b/lib/cmd/start.js
@@ -26,12 +26,15 @@

     if (hasError) {
       try {
-        const [ stdout ] = yield exec('tail -n 100 ' + stderr);
+        const args = [ '-n', '100', stderr ];
+        this.logger.error('tail %s', args.join(' '));
+        const [ stdout ] = yield execFile('tail', args);
         this.logger.error('Got error when startup: ');
         this.logger.error(stdout);
-      } catch (_) {
-        // nothing
+      } catch (err) {
+        this.logger.error('ignore tail error: %s', err);
       }
+
       isSuccess = ignoreStdErr;
       this.logger.error('Start got error, see %s', stderr);
       this.logger.error('Or use `--ignore-stderr` to ignore stderr at startup.');


Element Desktop is a Matrix client for desktop platforms. Element Desktop versions 1.11.70 through 1.11.80 contain a vulnerability which can, under specially crafted conditions, lead to the access token becoming exposed to third parties. At least one vector has been identified internally, involving malicious widgets, but other vectors may exist. Users are strongly advised to upgrade to version 1.11.81 to remediate the issue. As a workaround, avoid granting permissions to untrusted widgets.

export function setupMediaAuth(window: BrowserWindow): void {
    session.defaultSession.webRequest.onBeforeRequest(async (req, callback) => {
        // This handler emulates the element-web service worker, where URLs are rewritten late in the request
        // for backwards compatibility. As authenticated media becomes more prevalent, this should be replaced
        // by the app using authenticated URLs from the outset.
        let url = req.url;
        if (!url.includes("/_matrix/media/v3/download") && !url.includes("/_matrix/media/v3/thumbnail")) {
            return callback({}); // not a URL we care about
        }

        const supportedVersions = await getSupportedVersions(window);
        // We have to check that the access token is truthy otherwise we'd be intercepting pre-login media request too,
        // e.g. those required for SSO button icons.
        const accessToken = await getAccessToken(window);
        if (supportedVersions.includes("v1.11") && accessToken) {
            url = url.replace(/\/media\/v3\/(.*)\//, "/client/v1/media/$1/");
            return callback({ redirectURL: url });
        } else {
            return callback({}); // no support == no modification
        }
    });

    session.defaultSession.webRequest.onBeforeSendHeaders(async (req, callback) => {
        if (!req.url.includes("/_matrix/client/v1/media")) {
            return callback({}); // invoke unmodified
        }

        // Only add authorization header to authenticated media URLs. This emulates the service worker
        // behaviour in element-web.
        const accessToken = await getAccessToken(window);
        // `accessToken` can be falsy, but if we're trying to download media without authentication
        // then we should expect failure anyway.
        const headers = { ...req.requestHeaders, Authorization: `Bearer ${accessToken}` };
        return callback({ requestHeaders: headers });
    });
}

export function setupMediaAuth(window: BrowserWindow): void {
    session.defaultSession.webRequest.onBeforeRequest(async (req, callback) => {
        // This handler emulates the element-web service worker, where URLs are rewritten late in the request
        // for backwards compatibility. As authenticated media becomes more prevalent, this should be replaced
        // by the app using authenticated URLs from the outset.
        try {
            const url = new URL(req.url);
            if (
                !url.pathname.startsWith("/_matrix/media/v3/download") &&
                !url.pathname.startsWith("/_matrix/media/v3/thumbnail")
            ) {
                return callback({}); // not a URL we care about
            }

            const supportedVersions = await getSupportedVersions(window);
            // We have to check that the access token is truthy otherwise we'd be intercepting pre-login media request too,
            // e.g. those required for SSO button icons.
            const accessToken = await getAccessToken(window);
            if (supportedVersions.includes("v1.11") && accessToken) {
                url.href = url.href.replace(/\/media\/v3\/(.*)\//, "/client/v1/media/$1/");
                return callback({ redirectURL: url.toString() });
            } else {
                return callback({}); // no support == no modification
            }
        } catch (e) {
            console.error(e);
        }
    });

    session.defaultSession.webRequest.onBeforeSendHeaders(async (req, callback) => {
        try {
            const url = new URL(req.url);
            if (!url.pathname.startsWith("/_matrix/client/v1/media")) {
                return callback({}); // invoke unmodified
            }

            // Is this request actually going to the homeserver?
            // We don't combine this check with the one above on purpose.
            // We're fetching the homeserver url through IPC and should do so
            // as sparingly as possible.
            const homeserver = await getHomeserverUrl(window);
            const isRequestToHomeServer = homeserver && url.origin === new URL(homeserver).origin;
            if (!isRequestToHomeServer) {
                return callback({}); // invoke unmodified
            }

            // Only add authorization header to authenticated media URLs. This emulates the service worker
            // behaviour in element-web.
            const accessToken = await getAccessToken(window);
            // `accessToken` can be falsy, but if we're trying to download media without authentication
            // then we should expect failure anyway.
            const headers = { ...req.requestHeaders, Authorization: `Bearer ${accessToken}` };
            return callback({ requestHeaders: headers });
        } catch (e) {
            console.error(e);
        }
    });
}

--- a/src/media-auth.ts
+++ b/src/media-auth.ts
@@ -3,34 +3,56 @@
         // This handler emulates the element-web service worker, where URLs are rewritten late in the request
         // for backwards compatibility. As authenticated media becomes more prevalent, this should be replaced
         // by the app using authenticated URLs from the outset.
-        let url = req.url;
-        if (!url.includes("/_matrix/media/v3/download") && !url.includes("/_matrix/media/v3/thumbnail")) {
-            return callback({}); // not a URL we care about
-        }
+        try {
+            const url = new URL(req.url);
+            if (
+                !url.pathname.startsWith("/_matrix/media/v3/download") &&
+                !url.pathname.startsWith("/_matrix/media/v3/thumbnail")
+            ) {
+                return callback({}); // not a URL we care about
+            }

-        const supportedVersions = await getSupportedVersions(window);
-        // We have to check that the access token is truthy otherwise we'd be intercepting pre-login media request too,
-        // e.g. those required for SSO button icons.
-        const accessToken = await getAccessToken(window);
-        if (supportedVersions.includes("v1.11") && accessToken) {
-            url = url.replace(/\/media\/v3\/(.*)\//, "/client/v1/media/$1/");
-            return callback({ redirectURL: url });
-        } else {
-            return callback({}); // no support == no modification
+            const supportedVersions = await getSupportedVersions(window);
+            // We have to check that the access token is truthy otherwise we'd be intercepting pre-login media request too,
+            // e.g. those required for SSO button icons.
+            const accessToken = await getAccessToken(window);
+            if (supportedVersions.includes("v1.11") && accessToken) {
+                url.href = url.href.replace(/\/media\/v3\/(.*)\//, "/client/v1/media/$1/");
+                return callback({ redirectURL: url.toString() });
+            } else {
+                return callback({}); // no support == no modification
+            }
+        } catch (e) {
+            console.error(e);
         }
     });

     session.defaultSession.webRequest.onBeforeSendHeaders(async (req, callback) => {
-        if (!req.url.includes("/_matrix/client/v1/media")) {
-            return callback({}); // invoke unmodified
+        try {
+            const url = new URL(req.url);
+            if (!url.pathname.startsWith("/_matrix/client/v1/media")) {
+                return callback({}); // invoke unmodified
+            }
+
+            // Is this request actually going to the homeserver?
+            // We don't combine this check with the one above on purpose.
+            // We're fetching the homeserver url through IPC and should do so
+            // as sparingly as possible.
+            const homeserver = await getHomeserverUrl(window);
+            const isRequestToHomeServer = homeserver && url.origin === new URL(homeserver).origin;
+            if (!isRequestToHomeServer) {
+                return callback({}); // invoke unmodified
+            }
+
+            // Only add authorization header to authenticated media URLs. This emulates the service worker
+            // behaviour in element-web.
+            const accessToken = await getAccessToken(window);
+            // `accessToken` can be falsy, but if we're trying to download media without authentication
+            // then we should expect failure anyway.
+            const headers = { ...req.requestHeaders, Authorization: `Bearer ${accessToken}` };
+            return callback({ requestHeaders: headers });
+        } catch (e) {
+            console.error(e);
         }
-
-        // Only add authorization header to authenticated media URLs. This emulates the service worker
-        // behaviour in element-web.
-        const accessToken = await getAccessToken(window);
-        // `accessToken` can be falsy, but if we're trying to download media without authentication
-        // then we should expect failure anyway.
-        const headers = { ...req.requestHeaders, Authorization: `Bearer ${accessToken}` };
-        return callback({ requestHeaders: headers });
     });
 }


xmldom is an open source pure JavaScript W3C standard-based (XML DOM Level 2 Core) DOMParser and XMLSerializer module. xmldom versions 0.6.0 and older do not correctly escape special characters when serializing elements removed from their ancestor. This may lead to unexpected syntactic changes during XML processing in some downstream applications. This issue has been resolved in version 0.7.0. As a workaround downstream applications can validate the input and reject the maliciously crafted documents.

Improper Encoding or Escaping of Output

The product prepares a structured message for communication with another component, but encoding or escaping of the data is either missing or done incorrectly. As a result, the intended structure of the message is not preserved.

function serializeToString(node,buf,isHTML,nodeFilter,visibleNamespaces){
	if (!visibleNamespaces) {
		visibleNamespaces = [];
	}

	if(nodeFilter){
		node = nodeFilter(node);
		if(node){
			if(typeof node == 'string'){
				buf.push(node);
				return;
			}
		}else{
			return;
		}
		//buf.sort.apply(attrs, attributeSorter);
	}

	switch(node.nodeType){
	case ELEMENT_NODE:
		var attrs = node.attributes;
		var len = attrs.length;
		var child = node.firstChild;
		var nodeName = node.tagName;

		isHTML = NAMESPACE.isHTML(node.namespaceURI) || isHTML

		var prefixedNodeName = nodeName
		if (!isHTML && !node.prefix && node.namespaceURI) {
			var defaultNS
			for (var ai = 0; ai < attrs.length; ai++) {
				if (attrs.item(ai).name === 'xmlns') {
					defaultNS = attrs.item(ai).value
					break
				}
			}
			if (defaultNS !== node.namespaceURI) {
				for (var nsi = visibleNamespaces.length - 1; nsi >= 0; nsi--) {
					var namespace = visibleNamespaces[nsi]
					if (namespace.namespace === node.namespaceURI) {
						if (namespace.prefix) {
							prefixedNodeName = namespace.prefix + ':' + nodeName
						}
						break
					}
				}
			}
		}

		buf.push('<', prefixedNodeName);

		for(var i=0;i<len;i++){
			// add namespaces for attributes
			var attr = attrs.item(i);
			if (attr.prefix == 'xmlns') {
				visibleNamespaces.push({ prefix: attr.localName, namespace: attr.value });
			}else if(attr.nodeName == 'xmlns'){
				visibleNamespaces.push({ prefix: '', namespace: attr.value });
			}
		}

		for(var i=0;i<len;i++){
			var attr = attrs.item(i);
			if (needNamespaceDefine(attr,isHTML, visibleNamespaces)) {
				var prefix = attr.prefix||'';
				var uri = attr.namespaceURI;
				var ns = prefix ? ' xmlns:' + prefix : " xmlns";
				buf.push(ns, '="' , uri , '"');
				visibleNamespaces.push({ prefix: prefix, namespace:uri });
			}
			serializeToString(attr,buf,isHTML,nodeFilter,visibleNamespaces);
		}

		// add namespace for current node
		if (nodeName === prefixedNodeName && needNamespaceDefine(node, isHTML, visibleNamespaces)) {
			var prefix = node.prefix||'';
			var uri = node.namespaceURI;
			var ns = prefix ? ' xmlns:' + prefix : " xmlns";
			buf.push(ns, '="' , uri , '"');
			visibleNamespaces.push({ prefix: prefix, namespace:uri });
		}

		if(child || isHTML && !/^(?:meta|link|img|br|hr|input)$/i.test(nodeName)){
			buf.push('>');
			//if is cdata child node
			if(isHTML && /^script$/i.test(nodeName)){
				while(child){
					if(child.data){
						buf.push(child.data);
					}else{
						serializeToString(child, buf, isHTML, nodeFilter, visibleNamespaces.slice());
					}
					child = child.nextSibling;
				}
			}else
			{
				while(child){
					serializeToString(child, buf, isHTML, nodeFilter, visibleNamespaces.slice());
					child = child.nextSibling;
				}
			}
			buf.push('</',prefixedNodeName,'>');
		}else{
			buf.push('/>');
		}
		// remove added visible namespaces
		//visibleNamespaces.length = startVisibleNamespaces;
		return;
	case DOCUMENT_NODE:
	case DOCUMENT_FRAGMENT_NODE:
		var child = node.firstChild;
		while(child){
			serializeToString(child, buf, isHTML, nodeFilter, visibleNamespaces.slice());
			child = child.nextSibling;
		}
		return;
	case ATTRIBUTE_NODE:
		/**
		 * Well-formedness constraint: No < in Attribute Values
		 * The replacement text of any entity referred to directly or indirectly in an attribute value must not contain a <.
		 * @see https://www.w3.org/TR/xml/#CleanAttrVals
		 * @see https://www.w3.org/TR/xml/#NT-AttValue
		 */
		return buf.push(' ', node.name, '="', node.value.replace(/[<&"]/g,_xmlEncoder), '"');
	case TEXT_NODE:
		/**
		 * The ampersand character (&) and the left angle bracket (<) must not appear in their literal form,
		 * except when used as markup delimiters, or within a comment, a processing instruction, or a CDATA section.
		 * If they are needed elsewhere, they must be escaped using either numeric character references or the strings
		 * `&` and `<` respectively.
		 * The right angle bracket (>) may be represented using the string " > ", and must, for compatibility,
		 * be escaped using either `>` or a character reference when it appears in the string `]]>` in content,
		 * when that string is not marking the end of a CDATA section.
		 *
		 * In the content of elements, character data is any string of characters
		 * which does not contain the start-delimiter of any markup
		 * and does not include the CDATA-section-close delimiter, `]]>`.
		 *
		 * @see https://www.w3.org/TR/xml/#NT-CharData
		 */
		return buf.push(node.data
			.replace(/[<&]/g,_xmlEncoder)
			.replace(/]]>/g, ']]>')
		);
	case CDATA_SECTION_NODE:
		return buf.push( '<![CDATA[',node.data,']]>');
	case COMMENT_NODE:
		return buf.push( "<!--",node.data,"-->");
	case DOCUMENT_TYPE_NODE:
		var pubid = node.publicId;
		var sysid = node.systemId;
		buf.push('<!DOCTYPE ',node.name);
		if(pubid){
			buf.push(' PUBLIC ', pubid);
			if (sysid && sysid!='.') {
				buf.push(' ', sysid);
			}
			buf.push('>');
		}else if(sysid && sysid!='.'){
			buf.push(' SYSTEM ', sysid, '>');
		}else{
			var sub = node.internalSubset;
			if(sub){
				buf.push(" [",sub,"]");
			}
			buf.push(">");
		}
		return;
	case PROCESSING_INSTRUCTION_NODE:
		return buf.push( "<?",node.target," ",node.data,"?>");
	case ENTITY_REFERENCE_NODE:
		return buf.push( '&',node.nodeName,';');
	//case ENTITY_NODE:
	//case NOTATION_NODE:
	default:
		buf.push('??',node.nodeName);
	}
}

function serializeToString(node,buf,isHTML,nodeFilter,visibleNamespaces){
	if (!visibleNamespaces) {
		visibleNamespaces = [];
	}

	if(nodeFilter){
		node = nodeFilter(node);
		if(node){
			if(typeof node == 'string'){
				buf.push(node);
				return;
			}
		}else{
			return;
		}
		//buf.sort.apply(attrs, attributeSorter);
	}

	switch(node.nodeType){
	case ELEMENT_NODE:
		var attrs = node.attributes;
		var len = attrs.length;
		var child = node.firstChild;
		var nodeName = node.tagName;

		isHTML = NAMESPACE.isHTML(node.namespaceURI) || isHTML

		var prefixedNodeName = nodeName
		if (!isHTML && !node.prefix && node.namespaceURI) {
			var defaultNS
			for (var ai = 0; ai < attrs.length; ai++) {
				if (attrs.item(ai).name === 'xmlns') {
					defaultNS = attrs.item(ai).value
					break
				}
			}
			if (defaultNS !== node.namespaceURI) {
				for (var nsi = visibleNamespaces.length - 1; nsi >= 0; nsi--) {
					var namespace = visibleNamespaces[nsi]
					if (namespace.namespace === node.namespaceURI) {
						if (namespace.prefix) {
							prefixedNodeName = namespace.prefix + ':' + nodeName
						}
						break
					}
				}
			}
		}

		buf.push('<', prefixedNodeName);

		for(var i=0;i<len;i++){
			// add namespaces for attributes
			var attr = attrs.item(i);
			if (attr.prefix == 'xmlns') {
				visibleNamespaces.push({ prefix: attr.localName, namespace: attr.value });
			}else if(attr.nodeName == 'xmlns'){
				visibleNamespaces.push({ prefix: '', namespace: attr.value });
			}
		}

		for(var i=0;i<len;i++){
			var attr = attrs.item(i);
			if (needNamespaceDefine(attr,isHTML, visibleNamespaces)) {
				var prefix = attr.prefix||'';
				var uri = attr.namespaceURI;
				addSerializedAttribute(buf, prefix ? 'xmlns:' + prefix : "xmlns", uri);
				visibleNamespaces.push({ prefix: prefix, namespace:uri });
			}
			serializeToString(attr,buf,isHTML,nodeFilter,visibleNamespaces);
		}

		// add namespace for current node
		if (nodeName === prefixedNodeName && needNamespaceDefine(node, isHTML, visibleNamespaces)) {
			var prefix = node.prefix||'';
			var uri = node.namespaceURI;
			addSerializedAttribute(buf, prefix ? 'xmlns:' + prefix : "xmlns", uri);
			visibleNamespaces.push({ prefix: prefix, namespace:uri });
		}

		if(child || isHTML && !/^(?:meta|link|img|br|hr|input)$/i.test(nodeName)){
			buf.push('>');
			//if is cdata child node
			if(isHTML && /^script$/i.test(nodeName)){
				while(child){
					if(child.data){
						buf.push(child.data);
					}else{
						serializeToString(child, buf, isHTML, nodeFilter, visibleNamespaces.slice());
					}
					child = child.nextSibling;
				}
			}else
			{
				while(child){
					serializeToString(child, buf, isHTML, nodeFilter, visibleNamespaces.slice());
					child = child.nextSibling;
				}
			}
			buf.push('</',prefixedNodeName,'>');
		}else{
			buf.push('/>');
		}
		// remove added visible namespaces
		//visibleNamespaces.length = startVisibleNamespaces;
		return;
	case DOCUMENT_NODE:
	case DOCUMENT_FRAGMENT_NODE:
		var child = node.firstChild;
		while(child){
			serializeToString(child, buf, isHTML, nodeFilter, visibleNamespaces.slice());
			child = child.nextSibling;
		}
		return;
	case ATTRIBUTE_NODE:
		return addSerializedAttribute(buf, node.name, node.value);
	case TEXT_NODE:
		/**
		 * The ampersand character (&) and the left angle bracket (<) must not appear in their literal form,
		 * except when used as markup delimiters, or within a comment, a processing instruction, or a CDATA section.
		 * If they are needed elsewhere, they must be escaped using either numeric character references or the strings
		 * `&` and `<` respectively.
		 * The right angle bracket (>) may be represented using the string " > ", and must, for compatibility,
		 * be escaped using either `>` or a character reference when it appears in the string `]]>` in content,
		 * when that string is not marking the end of a CDATA section.
		 *
		 * In the content of elements, character data is any string of characters
		 * which does not contain the start-delimiter of any markup
		 * and does not include the CDATA-section-close delimiter, `]]>`.
		 *
		 * @see https://www.w3.org/TR/xml/#NT-CharData
		 */
		return buf.push(node.data
			.replace(/[<&]/g,_xmlEncoder)
			.replace(/]]>/g, ']]>')
		);
	case CDATA_SECTION_NODE:
		return buf.push( '<![CDATA[',node.data,']]>');
	case COMMENT_NODE:
		return buf.push( "<!--",node.data,"-->");
	case DOCUMENT_TYPE_NODE:
		var pubid = node.publicId;
		var sysid = node.systemId;
		buf.push('<!DOCTYPE ',node.name);
		if(pubid){
			buf.push(' PUBLIC ', pubid);
			if (sysid && sysid!='.') {
				buf.push(' ', sysid);
			}
			buf.push('>');
		}else if(sysid && sysid!='.'){
			buf.push(' SYSTEM ', sysid, '>');
		}else{
			var sub = node.internalSubset;
			if(sub){
				buf.push(" [",sub,"]");
			}
			buf.push(">");
		}
		return;
	case PROCESSING_INSTRUCTION_NODE:
		return buf.push( "<?",node.target," ",node.data,"?>");
	case ENTITY_REFERENCE_NODE:
		return buf.push( '&',node.nodeName,';');
	//case ENTITY_NODE:
	//case NOTATION_NODE:
	default:
		buf.push('??',node.nodeName);
	}
}

/**
 * Well-formed constraint: No < in Attribute Values
 * The replacement text of any entity referred to directly or indirectly in an attribute value must not contain a <.
 * @see https://www.w3.org/TR/xml/#CleanAttrVals
 * @see https://www.w3.org/TR/xml/#NT-AttValue
 */
function addSerializedAttribute(buf, qualifiedName, value) {
	buf.push(' ', qualifiedName, '="', value.replace(/[<&"]/g,_xmlEncoder), '"')
}

--- a/lib/dom.js
+++ b/lib/dom.js
@@ -64,8 +64,7 @@
 			if (needNamespaceDefine(attr,isHTML, visibleNamespaces)) {
 				var prefix = attr.prefix||'';
 				var uri = attr.namespaceURI;
-				var ns = prefix ? ' xmlns:' + prefix : " xmlns";
-				buf.push(ns, '="' , uri , '"');
+				addSerializedAttribute(buf, prefix ? 'xmlns:' + prefix : "xmlns", uri);
 				visibleNamespaces.push({ prefix: prefix, namespace:uri });
 			}
 			serializeToString(attr,buf,isHTML,nodeFilter,visibleNamespaces);
@@ -75,8 +74,7 @@
 		if (nodeName === prefixedNodeName && needNamespaceDefine(node, isHTML, visibleNamespaces)) {
 			var prefix = node.prefix||'';
 			var uri = node.namespaceURI;
-			var ns = prefix ? ' xmlns:' + prefix : " xmlns";
-			buf.push(ns, '="' , uri , '"');
+			addSerializedAttribute(buf, prefix ? 'xmlns:' + prefix : "xmlns", uri);
 			visibleNamespaces.push({ prefix: prefix, namespace:uri });
 		}

@@ -115,13 +113,7 @@
 		}
 		return;
 	case ATTRIBUTE_NODE:
-		/**
-		 * Well-formedness constraint: No < in Attribute Values
-		 * The replacement text of any entity referred to directly or indirectly in an attribute value must not contain a <.
-		 * @see https://www.w3.org/TR/xml/#CleanAttrVals
-		 * @see https://www.w3.org/TR/xml/#NT-AttValue
-		 */
-		return buf.push(' ', node.name, '="', node.value.replace(/[<&"]/g,_xmlEncoder), '"');
+		return addSerializedAttribute(buf, node.name, node.value);
 	case TEXT_NODE:
 		/**
 		 * The ampersand character (&) and the left angle bracket (<) must not appear in their literal form,

--- /dev/null
+++ b/lib/dom.js
@@ -0,0 +1,9 @@
+/**
+ * Well-formed constraint: No < in Attribute Values
+ * The replacement text of any entity referred to directly or indirectly in an attribute value must not contain a <.
+ * @see https://www.w3.org/TR/xml/#CleanAttrVals
+ * @see https://www.w3.org/TR/xml/#NT-AttValue
+ */
+function addSerializedAttribute(buf, qualifiedName, value) {
+	buf.push(' ', qualifiedName, '="', value.replace(/[<&"]/g,_xmlEncoder), '"')
+}

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

cd /workspace/xmldom
git apply --whitespace=nowarn /workspace/test.patch /workspace/fix.patch
npx jest -t "should escape special characters in namespace attributes" test/dom/serializer.test.js

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

cd /workspace/xmldom
git apply --whitespace=nowarn /workspace/fix.patch
npx jest  test/dom/serializer.test.js


Improper Input Validation in GitHub repository mintplex-labs/anything-llm prior to 0.1.0.

Improper Input Validation

The product receives input or data, but it does
        not validate or incorrectly validates that the input has the
        properties that are required to process the data safely and
        correctly.

@api.route('/process', methods=['POST'])
def process_file():
  content = request.json
  target_filename = content.get('filename')
  print(f"Processing {target_filename}")
  success, reason = process_single(WATCH_DIRECTORY, target_filename)
  return json.dumps({'filename': target_filename, 'success': success, 'reason': reason})

@api.route('/process', methods=['POST'])
def process_file():
  content = request.json
  target_filename = os.path.normpath(content.get('filename')).lstrip(os.pardir + os.sep)
  print(f"Processing {target_filename}")
  success, reason = process_single(WATCH_DIRECTORY, target_filename)
  return json.dumps({'filename': target_filename, 'success': success, 'reason': reason})

--- a/collector/api.py
+++ b/collector/api.py
@@ -1,7 +1,7 @@
 @api.route('/process', methods=['POST'])
 def process_file():
   content = request.json
-  target_filename = content.get('filename')
+  target_filename = os.path.normpath(content.get('filename')).lstrip(os.pardir + os.sep)
   print(f"Processing {target_filename}")
   success, reason = process_single(WATCH_DIRECTORY, target_filename)
   return json.dumps({'filename': target_filename, 'success': success, 'reason': reason})

--- /dev/null
+++ b/collector/api.py
@@ -0,0 +1 @@
+import os