From 6ddc35692c2d76f1be23cc7d3d07aee741bfe35d Mon Sep 17 00:00:00 2001 From: Ondrej Lukas Date: Mon, 23 Feb 2026 17:17:24 +0100 Subject: [PATCH 1/3] feat: Add goal description validation to the config parser and update an example attacker goal with a specific C&C IP. --- netsecgame/game/config_parser.py | 33 ++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/netsecgame/game/config_parser.py b/netsecgame/game/config_parser.py index 8aace5ec..9683cfea 100644 --- a/netsecgame/game/config_parser.py +++ b/netsecgame/game/config_parser.py @@ -304,11 +304,13 @@ def get_goal_description(self, agent_role)->str: case "Attacker": try: description = self.config['coordinator']['agents'][agent_role]["goal"]["description"] + self.validate_goal_description(agent_role, description) except KeyError: description = "" case "Defender": try: description = self.config['coordinator']['agents'][agent_role]["goal"]["description"] + self.validate_goal_description(agent_role, description) except KeyError: description = "" case "Benign": @@ -317,6 +319,37 @@ def get_goal_description(self, agent_role)->str: raise ValueError(f"Unsupported agent role: {agent_role}") return description + def validate_goal_description(self, agent_role: str, description: str): + """ + Warns if the goal description misses key targets from the actual win conditions. + """ + if not description: + return # No description to validate + + description_lower = description.lower() + missing_elements = [] + + try: + win_conditions = self.config['coordinator']['agents'][agent_role]['goal'] + except KeyError: + return + + # Check controlled hosts + for host in win_conditions.get('controlled_hosts', []): + if str(host) not in description_lower and str(host) != "random": + missing_elements.append(f"Controlled Host: {host}") + + # Check known data targets + for host, data_set in win_conditions.get('known_data', {}).items(): + if str(host) not in description_lower and str(host) != "random": + # Only require host IP if it isn't "random" + missing_elements.append(f"Target Host IP defined for data: {host}") + + if missing_elements: + self.logger.warning( + f"[{agent_role}] Goal description '{description}' might be missing some actual win condition targets: {missing_elements}" + ) + def get_rewards(self, reward_names:list, default_value=0)->dict: "Reads configuration for rewards for cases listed in 'rewards_names'" rewards = {} From 419ac5370e2bcf57430ce33c8f2e799cc3c83640 Mon Sep 17 00:00:00 2001 From: Ondrej Lukas Date: Wed, 25 Feb 2026 11:29:01 +0100 Subject: [PATCH 2/3] Add IP to the goal description --- examples/example_task_configuration.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/example_task_configuration.yaml b/examples/example_task_configuration.yaml index 933c3978..7522856e 100644 --- a/examples/example_task_configuration.yaml +++ b/examples/example_task_configuration.yaml @@ -9,7 +9,7 @@ coordinator: Attacker: # Configuration of 'Attacker' agents max_steps: 50 goal: - description: "Exfiltrate data from Samba server to remote C&C server." + description: "Exfiltrate data from Samba server to remote C&C server (213.47.23.195)." is_any_part_of_goal_random: True known_networks: [] known_hosts: [] From 5ec26a4ef64d28d613d06723a8ebdf41f790e5e7 Mon Sep 17 00:00:00 2001 From: Ondrej Lukas Date: Wed, 25 Feb 2026 11:42:49 +0100 Subject: [PATCH 3/3] Update requiremetns to the latest cyst-core release --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index ef9d5bd0..899f2b95 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -30,7 +30,7 @@ requires-python = ">=3.12" # dependencies allowing to run the game server and the simulation server = [ "aiohttp>=3.11", - "cyst-core>=0.5.0", + "cyst-core>=0.6.6", "Faker>=23.2", "numpy>=1.26", "PyYAML>=6.0",