From 5070ce39c23747aba2cc80bce88b6b31f42e6764 Mon Sep 17 00:00:00 2001 From: StylusFrost Date: Mon, 1 Jun 2026 19:40:22 +0200 Subject: [PATCH] fix(sdk): guard built-in providers in is_tool_wrapper_provider - Short-circuit on is_builtin_provider before loading entry points - Prevent same-name plug-ins from flipping a built-in onto the tool-wrapper path - Avoid executing plug-in code via ep.load() for built-in names - Add regression test asserting ep.load is never called --- prowler/lib/check/tool_wrapper.py | 5 +++++ tests/lib/check/tool_wrapper_test.py | 14 ++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/prowler/lib/check/tool_wrapper.py b/prowler/lib/check/tool_wrapper.py index f00afd35d6..a1d606594e 100644 --- a/prowler/lib/check/tool_wrapper.py +++ b/prowler/lib/check/tool_wrapper.py @@ -13,6 +13,7 @@ and `prowler.providers.common.provider` without forming an import cycle. import importlib.metadata from prowler.lib.check.external_tool_providers import EXTERNAL_TOOL_PROVIDERS +from prowler.providers.common.builtin import is_builtin_provider # Module-level cache for entry-point classes consulted by this helper. # Independent of `Provider._ep_providers` to keep this module leaf — the cost @@ -53,5 +54,9 @@ def is_tool_wrapper_provider(provider: str) -> bool: """ if provider in EXTERNAL_TOOL_PROVIDERS: return True + # Built-in wins: short-circuit before ep.load() so a same-name plug-in + # cannot flip a built-in onto the tool-wrapper path or run its code. + if is_builtin_provider(provider): + return False cls = _load_ep_class(provider) return bool(cls and getattr(cls, "is_external_tool_provider", False)) diff --git a/tests/lib/check/tool_wrapper_test.py b/tests/lib/check/tool_wrapper_test.py index ed3b897d8d..5f4f0c7f88 100644 --- a/tests/lib/check/tool_wrapper_test.py +++ b/tests/lib/check/tool_wrapper_test.py @@ -70,6 +70,20 @@ class TestIsToolWrapperProvider: assert is_tool_wrapper_provider("does-not-exist") is False + @patch("prowler.lib.check.tool_wrapper.importlib.metadata.entry_points") + def test_builtin_name_shortcircuits_before_loading_same_name_plugin(self, mock_eps): + """A plug-in registered under a built-in's name cannot flip the + built-in onto the tool-wrapper path, and its module is never loaded.""" + from prowler.lib.check.tool_wrapper import is_tool_wrapper_provider + + malicious = _make_entry_point("aws", MagicMock(is_external_tool_provider=True)) + mock_eps.return_value = [malicious] + + # `aws` is a built-in, so classification short-circuits to False... + assert is_tool_wrapper_provider("aws") is False + # ...and the shadowing plug-in's code is never executed via ep.load(). + malicious.load.assert_not_called() + class TestLoadEpClass: """_load_ep_class: cache, broken plug-ins, no-match."""