Skip to content

Commit b3503d4

Browse files
committed
snyk: sanitize options passed to --snyk-code-test-opts
... to avoid shell injection. Also provide `sanitize_opts_arg()` in `csmock.common.util` so that it can be reused by other plug-ins that support passing of custom options to the wrapped tools. Fixes: commit 73eddc1 Resolves: CVE-2024-2243 - command injection vulnerability in csmock-plugin-snyk Reviewed-by: jperezde <jperezde@redhat.com>
1 parent b90b8e8 commit b3503d4

2 files changed

Lines changed: 32 additions & 3 deletions

File tree

py/common/util.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
import os
1919
import re
20+
import shlex
2021

2122

2223
def shell_quote(str_in):
@@ -34,6 +35,30 @@ def shell_quote(str_in):
3435
return "\"" + str_out + "\""
3536

3637

38+
def arg_value_by_name(parser, args, arg_name):
39+
"""return value of an argument parsed by argparse.ArgumentParser"""
40+
for action in parser._actions:
41+
if arg_name in action.option_strings:
42+
return getattr(args, action.dest)
43+
44+
45+
def sanitize_opts_arg(parser, args, arg_name):
46+
"""sanitize command-line options passed to an option of argparse.ArgumentParser"""
47+
opts_str = arg_value_by_name(parser, args, arg_name)
48+
if opts_str is None:
49+
return None
50+
51+
# split, quote, and rejoin the options to avoid shell injection
52+
try:
53+
split_opts = shlex.split(args.snyk_code_test_opts)
54+
55+
# starting with Python 3.8, one can use shlex.join(split_opts)
56+
return ' '.join(shlex.quote(arg) for arg in split_opts)
57+
58+
except ValueError as e:
59+
parser.error(f"failed to parse value given to {arg_name}: {str(e)}")
60+
61+
3762
def strlist_to_shell_cmd(cmd_in, escape_special=False):
3863
def translate_one(i):
3964
if escape_special:

py/plugins/snyk.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import os
1919

2020
from csmock.common.snyk import snyk_write_analysis_meta
21+
from csmock.common.util import sanitize_opts_arg
2122

2223

2324
# default URL to download snyk binary executable
@@ -84,6 +85,9 @@ def handle_args(self, parser, args, props):
8485
if not self.enabled:
8586
return
8687

88+
# sanitize options passed to --snyk-code-test-opts to avoid shell injection
89+
self.snyk_code_test_opts = sanitize_opts_arg(parser, args, "--snyk-code-test-opts")
90+
8791
# check whether we have access to snyk authentication token
8892
self.auth_token_src = os.path.expanduser(args.snyk_auth)
8993
if not os.access(self.auth_token_src, os.R_OK):
@@ -164,9 +168,9 @@ def scan_hook(results, mock, props):
164168
# command to run snyk code
165169
cmd = f"{self.snyk_bin} code test -d {SNYK_SCAN_DIR}"
166170

167-
# if we use the --snyk-code-test-opts flags, we append the flags to the SNYK CLI code
168-
if args.snyk_code_test_opts:
169-
cmd += f" {args.snyk_code_test_opts}"
171+
if self.snyk_code_test_opts:
172+
# propagate options given to --snyk-code-test-opts
173+
cmd += f" {self.snyk_code_test_opts}"
170174

171175
cmd += f" --sarif-file-output={SNYK_OUTPUT} >/dev/null 2>{SNYK_LOG}"
172176

0 commit comments

Comments
 (0)