fix(security): replace yaml.full_load with yaml.safe_load to prevent RCE (#1242)

Signed-off-by: Nitesh <nitesh@example.com>
Co-authored-by: Nitesh <nitesh@example.com>
This commit is contained in:
Nitesh Kumar
2026-04-22 09:50:56 -04:00
committed by GitHub
co-authored by Nitesh
parent e1d4f1edbb
commit a912f958e5
18 changed files with 26 additions and 26 deletions
@@ -34,7 +34,7 @@ class ApplicationOutageScenarioPlugin(AbstractScenarioPlugin):
) -> int:
try:
with open(scenario, "r") as f:
app_outage_config_yaml = yaml.full_load(f)
app_outage_config_yaml = yaml.safe_load(f)
scenario_config = app_outage_config_yaml["application_outage"]
pod_selector = get_yaml_item_value(
scenario_config, "pod_selector", "{}"
@@ -36,7 +36,7 @@ class ContainerScenarioPlugin(AbstractScenarioPlugin):
) -> int:
try:
with open(scenario, "r") as f:
cont_scenario_config = yaml.full_load(f)
cont_scenario_config = yaml.safe_load(f)
for kill_scenario in cont_scenario_config["scenarios"]:
future_snapshot = self.start_monitoring(
@@ -40,7 +40,7 @@ class HogsScenarioPlugin(AbstractScenarioPlugin):
scenario_telemetry: ScenarioTelemetry) -> int:
try:
with open(scenario, "r") as f:
scenario = yaml.full_load(f)
scenario = yaml.safe_load(f)
scenario_config = HogConfig.from_yaml_dict(scenario)
# Get node-name if provided
@@ -56,7 +56,7 @@ class KubevirtVmOutageScenarioPlugin(AbstractScenarioPlugin):
"""
try:
with open(scenario, "r") as f:
scenario_config = yaml.full_load(f)
scenario_config = yaml.safe_load(f)
self.init_clients(lib_telemetry.get_lib_kubernetes())
vmis_status = VmisStatus()
@@ -33,7 +33,7 @@ class ManagedClusterScenarioPlugin(AbstractScenarioPlugin):
scenario_telemetry: ScenarioTelemetry,
) -> int:
with open(scenario, "r") as f:
scenario = yaml.full_load(f)
scenario = yaml.safe_load(f)
for managedcluster_scenario in scenario["managedcluster_scenarios"]:
managedcluster_scenario_object = Scenarios(
lib_telemetry.get_lib_kubernetes()
@@ -57,7 +57,7 @@ class NodeActionsScenarioPlugin(AbstractScenarioPlugin):
scenario_telemetry: ScenarioTelemetry,
) -> int:
with open(scenario, "r") as f:
node_scenario_config = yaml.full_load(f)
node_scenario_config = yaml.safe_load(f)
for node_scenario in node_scenario_config["node_scenarios"]:
try:
node_scenario_object = self.get_node_scenario_object(
@@ -46,7 +46,7 @@ class PodDisruptionScenarioPlugin(AbstractScenarioPlugin):
) -> int:
try:
with open(scenario, "r") as f:
cont_scenario_config = yaml.full_load(f)
cont_scenario_config = yaml.safe_load(f)
for kill_scenario in cont_scenario_config:
kill_scenario_config = InputParams(kill_scenario["config"])
future_snapshot=self.start_monitoring(
@@ -40,7 +40,7 @@ class PvcScenarioPlugin(AbstractScenarioPlugin):
) -> int:
try:
with open(scenario, "r") as f:
config_yaml = yaml.full_load(f)
config_yaml = yaml.safe_load(f)
scenario_config = config_yaml["pvc_scenario"]
pvc_name = get_yaml_item_value(scenario_config, "pvc_name", "")
pod_name = get_yaml_item_value(scenario_config, "pod_name", "")
@@ -34,7 +34,7 @@ class ServiceDisruptionScenarioPlugin(AbstractScenarioPlugin):
) -> int:
try:
with open(scenario, "r") as f:
scenario_config_yaml = yaml.full_load(f)
scenario_config_yaml = yaml.safe_load(f)
for scenario in scenario_config_yaml["scenarios"]:
scenario_namespace = get_yaml_item_value(scenario, "namespace", "")
scenario_label = get_yaml_item_value(scenario, "label_selector", "")
@@ -41,7 +41,7 @@ class ShutDownScenarioPlugin(AbstractScenarioPlugin):
) -> int:
try:
with open(scenario, "r") as f:
shut_down_config_yaml = yaml.full_load(f)
shut_down_config_yaml = yaml.safe_load(f)
shut_down_config_scenario = shut_down_config_yaml[
"cluster_shut_down_scenario"
]
@@ -37,7 +37,7 @@ class TimeActionsScenarioPlugin(AbstractScenarioPlugin):
) -> int:
try:
with open(scenario, "r") as f:
scenario_config = yaml.full_load(f)
scenario_config = yaml.safe_load(f)
for time_scenario in scenario_config["time_scenarios"]:
object_type, object_names = self.skew_time(
time_scenario, lib_telemetry.get_lib_kubernetes()
@@ -46,7 +46,7 @@ class ZoneOutageScenarioPlugin(AbstractScenarioPlugin):
) -> int:
try:
with open(scenario, "r") as f:
zone_outage_config_yaml = yaml.full_load(f)
zone_outage_config_yaml = yaml.safe_load(f)
scenario_config = zone_outage_config_yaml["zone_outage"]
cloud_type = scenario_config["cloud_type"]
kube_check = get_yaml_item_value(scenario_config, "kube_check", True)
+1 -1
View File
@@ -80,7 +80,7 @@ def main(options, command: Optional[str]) -> int:
# Parse and read the config
if os.path.isfile(cfg):
with open(cfg, "r") as f:
config = yaml.full_load(f)
config = yaml.safe_load(f)
kubeconfig_path = os.path.expanduser(
get_yaml_item_value(config["kraken"], "kubeconfig_path", "")
)
@@ -38,7 +38,7 @@ class TestManagedClusterScenarioPlugin(unittest.TestCase):
@patch('time.time')
@patch('builtins.open', create=True)
@patch('yaml.full_load')
@patch('yaml.safe_load')
@patch('krkn.cerberus.get_status')
def test_run_multiple_actions_executes_all(self, mock_cerberus, mock_yaml, mock_open, mock_time):
"""
@@ -94,7 +94,7 @@ class TestManagedClusterScenarioPlugin(unittest.TestCase):
@patch('time.time')
@patch('builtins.open', create=True)
@patch('yaml.full_load')
@patch('yaml.safe_load')
def test_run_stops_on_first_error(self, mock_yaml, mock_open, mock_time):
"""
Test that run() returns 1 and stops executing on first error
@@ -146,7 +146,7 @@ class TestManagedClusterScenarioPlugin(unittest.TestCase):
@patch('builtins.open', create=True)
@patch('yaml.full_load')
@patch('yaml.safe_load')
def test_run_returns_error_when_actions_empty(self, mock_yaml, _mock_open):
"""
Test that run() returns 1 and logs an error when actions is an empty list
@@ -182,7 +182,7 @@ class TestManagedClusterScenarioPlugin(unittest.TestCase):
)
@patch('builtins.open', create=True)
@patch('yaml.full_load')
@patch('yaml.safe_load')
def test_run_returns_error_when_actions_none(self, mock_yaml, _mock_open):
"""
Test that run() returns 1 and logs an error when actions is None
+2 -2
View File
@@ -667,7 +667,7 @@ class TestNodeActionsScenarioPlugin(unittest.TestCase):
mock_common_funcs.get_node_by_name.return_value = ["test-node"]
mock_cerberus.get_status.return_value = None
with patch('yaml.full_load', return_value=scenario_yaml):
with patch('yaml.safe_load', return_value=scenario_yaml):
result = self.plugin.run(
"test-uuid",
"/path/to/scenario.yaml",
@@ -692,7 +692,7 @@ class TestNodeActionsScenarioPlugin(unittest.TestCase):
]
}
with patch('yaml.full_load', return_value=scenario_yaml):
with patch('yaml.safe_load', return_value=scenario_yaml):
result = self.plugin.run(
"test-uuid",
"/path/to/scenario.yaml",
+1 -1
View File
@@ -61,7 +61,7 @@ class TestShutDownScenarioPlugin(unittest.TestCase):
mock_time.side_effect = [1000, 2000]
self.mock_kubecli.list_nodes.return_value = ["node1", "node2"]
with patch('yaml.full_load', return_value=scenario_yaml):
with patch('yaml.safe_load', return_value=scenario_yaml):
with patch.object(self.plugin, 'cluster_shut_down') as mock_cluster_shutdown:
result = self.plugin.run(
"test-uuid",
+2 -2
View File
@@ -55,7 +55,7 @@ class TestTimeActionsScenarioPlugin(unittest.TestCase):
self.assertIn("disk quota exceeded", logged_msg)
self.assertNotIn("NameError", logged_msg)
@unittest.mock.patch('builtins.open', create=True)
@unittest.mock.patch('yaml.full_load')
@unittest.mock.patch('yaml.safe_load')
@unittest.mock.patch('logging.error')
def test_run_exception_handling_with_variable(self, mock_logging_error, mock_yaml, mock_open):
"""
@@ -86,7 +86,7 @@ class TestTimeActionsScenarioPlugin(unittest.TestCase):
self.assertIn("TimeActionsScenarioPlugin", error_call_args)
@unittest.mock.patch('builtins.open', create=True)
@unittest.mock.patch('yaml.full_load')
@unittest.mock.patch('yaml.safe_load')
def test_run_with_skew_time_exception(self, mock_yaml, mock_open):
"""
Test that run() handles exceptions from skew_time method
+4 -4
View File
@@ -55,7 +55,7 @@ class TestZoneOutageScenarioPlugin(unittest.TestCase):
self.assertEqual(len(result), 1)
@unittest.mock.patch('builtins.open', create=True)
@unittest.mock.patch('yaml.full_load')
@unittest.mock.patch('yaml.safe_load')
@unittest.mock.patch('krkn.scenario_plugins.zone_outage.zone_outage_scenario_plugin.gcp_node_scenarios')
@unittest.mock.patch('krkn.cerberus.publish_kraken_status')
def test_run_propagates_node_based_zone_failure(self, mock_cerberus, mock_gcp_scenarios, mock_yaml, mock_open):
@@ -102,7 +102,7 @@ class TestZoneOutageScenarioPlugin(unittest.TestCase):
self.assertEqual(result, 1)
@unittest.mock.patch('builtins.open', create=True)
@unittest.mock.patch('yaml.full_load')
@unittest.mock.patch('yaml.safe_load')
@unittest.mock.patch('krkn.scenario_plugins.zone_outage.zone_outage_scenario_plugin.gcp_node_scenarios')
@unittest.mock.patch('krkn.cerberus.publish_kraken_status')
def test_run_succeeds_when_node_based_zone_succeeds(self, mock_cerberus, mock_gcp_scenarios, mock_yaml, mock_open):
@@ -148,7 +148,7 @@ class TestZoneOutageScenarioPlugin(unittest.TestCase):
self.assertEqual(result, 0)
@unittest.mock.patch('builtins.open', create=True)
@unittest.mock.patch('yaml.full_load')
@unittest.mock.patch('yaml.safe_load')
@unittest.mock.patch('krkn.scenario_plugins.zone_outage.zone_outage_scenario_plugin.AWS')
@unittest.mock.patch('krkn.cerberus.publish_kraken_status')
def test_run_aws_network_based_zone(self, mock_cerberus, mock_aws_class, mock_yaml, mock_open):
@@ -186,7 +186,7 @@ class TestZoneOutageScenarioPlugin(unittest.TestCase):
self.assertEqual(result, 0)
@unittest.mock.patch('builtins.open', create=True)
@unittest.mock.patch('yaml.full_load')
@unittest.mock.patch('yaml.safe_load')
@unittest.mock.patch('krkn.scenario_plugins.zone_outage.zone_outage_scenario_plugin.AWS')
@unittest.mock.patch('krkn.cerberus.publish_kraken_status')
def test_run_aws_network_based_zone_failure(self, mock_cerberus, mock_aws_class, mock_yaml, mock_open):