CVE-2019-10800: Improper Neutralization of Argument Delimiters in a Command ('Argument Injection') (CWE-88)
value: This affects the package codecov before 2.0.16. The vulnerability occurs due to not sanitizing gcov arguments before being being provided to the popen method.
CWE description: The product constructs a string for a command to be executed by a separate component
in another control sphere, but it does not properly delimit the
intended arguments, options, or switches within that command string.
CVSS v3 base score: 6.5
Published: 2022-07-13T12:15Z
Repository: https://github.com/codecov/codecov-python
Language: Python
Files changed: codecov/__init__.py, tests/test.py
Commit date: 2020-02-19 09:36:10 -0500
Commit message: CE-1380_sanitize_args

Diff: diff --git a/codecov/__init__.py b/codecov/__init__.py
index 6b3205c..40ba7a7 100644
--- a/codecov/__init__.py
+++ b/codecov/__init__.py
@@ -32,10 +32,14 @@ COLOR = True
 
 is_merge_commit = re.compile(r'^Merge\s\w{40}\sinto\s\w{40}$')
 
 remove_token = re.compile(r'token=[^\&]+').sub
 
+def sanitize_arg(replacement, arg):
+    return re.sub(r'[\&]+', replacement, arg, 0, re.MULTILINE)
+
+
 ignored_path = re.compile(r'(/vendor)|'
                           r'(/js/generated/coverage)|'
                           r'(/__pycache__)|'
                           r'(/coverage/instrumented)|'
                           r'(/build/lib)|'
@@ -622,15 +626,15 @@ def main(*argv, **kwargs):
                 "-not -path './node_modules/**' "
                 "-not -path './vendor/**'"
             )
             write('==> Processing gcov (disable by -X gcov)')
             cmd = "find %s %s -type f -name '*.gcno' %s -exec %s -pb %s {} +" % (
-                  (codecov.gcov_root or root),
+                  (sanitize_arg('', codecov.gcov_root or root)),
                   dont_search_here,
                   " ".join(map(lambda a: "-not -path '%s'" % a, codecov.gcov_glob)),
-                  (codecov.gcov_exec or ''),
-                  (codecov.gcov_args or ''))
+                  (sanitize_arg('', codecov.gcov_exec or '')),
+                  (sanitize_arg('', codecov.gcov_args or '')))
             write('    Executing gcov (%s)' % cmd)
             try_to_run(cmd)
 
         # Collect Reports
         # ---------------
diff --git a/tests/test.py b/tests/test.py
index ed640c6..cf001d6 100644
--- a/tests/test.py
+++ b/tests/test.py
@@ -313,10 +313,13 @@ class TestUploader(unittest.TestCase):
         except AssertionError as e:
             self.assertEqual(str(e), "No coverage report found")
         else:
             raise Exception("Did not raise AssertionError")
 
+    def test_sanitize_arg(self):
+        self.assertEqual(codecov.sanitize_arg('', '& echo test > vuln1.txt'), ' echo test > vuln1.txt')
+
     @unittest.skipUnless(os.getenv('JENKINS_URL'), 'Skip Jenkins CI test')
     def test_ci_jenkins(self):
         self.set_env(BUILD_URL='https://....',
                      JENKINS_URL='https://....',
                      GIT_BRANCH='master',

Vulnerable code:                   (codecov.gcov_root or root),
                  (codecov.gcov_exec or ''),
                  (codecov.gcov_args or ''))
Fixed code: def sanitize_arg(replacement, arg):
    return re.sub(r'[\&]+', replacement, arg, 0, re.MULTILINE)


                  (sanitize_arg('', codecov.gcov_root or root)),
                  (sanitize_arg('', codecov.gcov_exec or '')),
                  (sanitize_arg('', codecov.gcov_args or '')))
    def test_sanitize_arg(self):
        self.assertEqual(codecov.sanitize_arg('', '& echo test > vuln1.txt'), ' echo test > vuln1.txt')