From 73eac07f4b1547e4652dcb6b38b12ad85116040d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartosz=20J=C4=99drecki?= Date: Tue, 7 Jul 2026 18:49:36 +0200 Subject: [PATCH 1/2] Disallow logging.conf from elsewhere than the app folder --- splunklib/searchcommands/environment.py | 6 +++++ .../searchcommands/test_builtin_options.py | 24 +++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/splunklib/searchcommands/environment.py b/splunklib/searchcommands/environment.py index 83ee939f4..5dec95e02 100644 --- a/splunklib/searchcommands/environment.py +++ b/splunklib/searchcommands/environment.py @@ -97,6 +97,12 @@ def configure_logging(logger_name, filename=None): global _current_logging_configuration_file filename = path.realpath(filename) + app_root_real = path.realpath(app_root) + if path.commonpath([filename, app_root_real]) != app_root_real: # pyright: ignore[reportUnknownArgumentType] + raise ValueError( + f'Logging configuration file "{filename}" is outside the app directory' + ) + if filename != _current_logging_configuration_file: working_directory = getcwd() chdir(app_root) diff --git a/tests/unit/searchcommands/test_builtin_options.py b/tests/unit/searchcommands/test_builtin_options.py index 911321251..dd18c0589 100644 --- a/tests/unit/searchcommands/test_builtin_options.py +++ b/tests/unit/searchcommands/test_builtin_options.py @@ -137,6 +137,30 @@ def test_logging_configuration(self): f"Expected ValueError, but logging_configuration={command.logging_configuration}" ) + # logging_configuration raises a value error for an existing absolute path outside the app directory (RCE guard) + try: + command.logging_configuration = os.path.join(package_directory, "__init__.py") + except ValueError: + pass + except BaseException as e: + pytest.fail(f"Expected ValueError, but {type(e)} was raised") + else: + pytest.fail( + f"Expected ValueError, but logging_configuration={command.logging_configuration}" + ) + + # logging_configuration raises a value error when a relative path traverses outside the app directory (RCE guard) + try: + command.logging_configuration = os.path.join("..", "..", "..", "__init__.py") + except ValueError: + pass + except BaseException as e: + pytest.fail(f"Expected ValueError, but {type(e)} was raised") + else: + pytest.fail( + f"Expected ValueError, but logging_configuration={command.logging_configuration}" + ) + def test_logging_level(self): rebase_environment("app_without_logging_configuration") command = StubbedSearchCommand() From 63f0de16625b9eb621b2c180d471d98bfdb3df41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartosz=20J=C4=99drecki?= Date: Mon, 17 Aug 2026 17:50:23 +0200 Subject: [PATCH 2/2] Try addressing PR comments --- splunklib/searchcommands/environment.py | 15 ++++++++++++++- .../unit/searchcommands/test_builtin_options.py | 17 +++++++++++++---- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/splunklib/searchcommands/environment.py b/splunklib/searchcommands/environment.py index 5dec95e02..474dacfeb 100644 --- a/splunklib/searchcommands/environment.py +++ b/splunklib/searchcommands/environment.py @@ -120,9 +120,22 @@ def configure_logging(logger_name, filename=None): _current_logging_configuration_file = None + +def _find_app_root(app_file: str) -> str: + """Return the app root directory for a search command script.""" + directory: str = path.abspath(path.dirname(app_file)) + while True: + parent, name = path.split(directory) + if name == "bin": + return parent + if parent == directory: + return path.dirname(path.abspath(path.dirname(app_file))) + directory = parent + + splunk_home = path.abspath(path.join(getcwd(), environ.get("SPLUNK_HOME", ""))) app_file = getattr(sys.modules["__main__"], "__file__", sys.executable) -app_root = path.dirname(path.abspath(path.dirname(app_file))) +app_root = _find_app_root(app_file) splunklib_logger, logging_configuration = configure_logging("splunklib") diff --git a/tests/unit/searchcommands/test_builtin_options.py b/tests/unit/searchcommands/test_builtin_options.py index dd18c0589..f2827c5ef 100644 --- a/tests/unit/searchcommands/test_builtin_options.py +++ b/tests/unit/searchcommands/test_builtin_options.py @@ -137,16 +137,25 @@ def test_logging_configuration(self): f"Expected ValueError, but logging_configuration={command.logging_configuration}" ) - # logging_configuration raises a value error for an existing absolute path outside the app directory (RCE guard) + inside_app_root_logging_configuration = os.path.join( + environment.app_root, "default", "logging.conf" + ) + command.logging_configuration = inside_app_root_logging_configuration + assert command.logging_configuration == inside_app_root_logging_configuration, ( + "logging_configuration should accept an absolute path inside the app directory" + ) + try: - command.logging_configuration = os.path.join(package_directory, "__init__.py") + command.logging_configuration = os.path.realpath(__file__) except ValueError: pass except BaseException as e: - pytest.fail(f"Expected ValueError, but {type(e)} was raised") + pytest.fail( + f"Expected ValueError for a path outside the app directory, but {type(e)} was raised" + ) else: pytest.fail( - f"Expected ValueError, but logging_configuration={command.logging_configuration}" + f"Expected ValueError for a path outside the app directory, but {command.logging_configuration=}" ) # logging_configuration raises a value error when a relative path traverses outside the app directory (RCE guard)