From 2ac88f23238a8ade7c8d38ad90c3ab198e748748 Mon Sep 17 00:00:00 2001 From: Srijan Jaiswal Date: Sat, 6 Jun 2026 12:34:21 +0530 Subject: [PATCH 1/2] fix: default-deny network policy when allowlist is empty Previously, an empty SECUSCAN_NETWORK_ALLOWLIST caused _init_default_policies() to automatically add 0.0.0.0/0 and ::/0 as allow-all rules, making the network policy enforcement illusory. Now, an empty allowlist means deny-all egress. Only explicitly listed CIDRs in the allowlist are permitted. The denylist continues to block RFC 1918 private addresses and cloud metadata IPs. Fixes #613 --- backend/secuscan/config.py | 2 +- backend/secuscan/network_policy.py | 8 +++----- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/backend/secuscan/config.py b/backend/secuscan/config.py index 2853354f..5685895a 100644 --- a/backend/secuscan/config.py +++ b/backend/secuscan/config.py @@ -63,7 +63,7 @@ class Settings(BaseSettings): admin_api_key: Optional[str] = None # Network Policy Configuration - network_allowlist: List[str] = [] # IPs/networks to allow (CIDR) + network_allowlist: List[str] = [] # IPs/networks to allow (CIDR); empty = deny all egress network_denylist: List[str] = [ # IPs/networks to deny (CIDR) "169.254.169.254/32", # AWS metadata "169.254.0.0/16", # Reserved/metadata diff --git a/backend/secuscan/network_policy.py b/backend/secuscan/network_policy.py index 21bf490f..db4af27f 100644 --- a/backend/secuscan/network_policy.py +++ b/backend/secuscan/network_policy.py @@ -398,11 +398,9 @@ def _init_default_policies(engine: NetworkPolicyEngine) -> None: except ValueError: logger.warning(f"Skipping invalid allowlist CIDR: {cidr}") - # Add system defaults (if allowlist is empty, add public internet) + # Warn if allowlist is empty — network policy defaults to deny-all egress if not settings.network_allowlist: logger.warning( - "SECUSCAN_NETWORK_ALLOWLIST is empty. Allowing all public IPs. " - "Configure this environment variable to restrict egress." + "SECUSCAN_NETWORK_ALLOWLIST is empty. All external network egress is blocked. " + "Configure this environment variable with CIDR ranges to allow outbound traffic." ) - engine.add_allow_rule("0.0.0.0/0", reason="Default allow all (configure SECUSCAN_NETWORK_ALLOWLIST)") - engine.add_allow_rule("::/0", reason="Default allow all IPv6") From 8f733718b15f98a0b79d624f052941526e8b8576 Mon Sep 17 00:00:00 2001 From: Srijan Jaiswal Date: Sat, 6 Jun 2026 14:01:40 +0530 Subject: [PATCH 2/2] fix: resolve pre-existing CI failures in workflows.py and frontend tests --- backend/secuscan/workflows.py | 1 + frontend/testing/unit/pages/ToolConfigDynamic.test.tsx | 5 +++++ frontend/testing/unit/pages/ToolConfigTimeout.test.tsx | 2 +- frontend/testing/unit/pages/Workflows.test.tsx | 10 +++++++++- 4 files changed, 16 insertions(+), 2 deletions(-) diff --git a/backend/secuscan/workflows.py b/backend/secuscan/workflows.py index eb98c598..c7ba88dc 100644 --- a/backend/secuscan/workflows.py +++ b/backend/secuscan/workflows.py @@ -72,6 +72,7 @@ def _should_run(self, now: datetime, last_run_at: str | None, schedule_seconds: return elapsed >= schedule_seconds async def _run_workflow(self, workflow_id: str, steps: List[Dict[str, Any]]): logger.info("Running workflow %s with %d step(s)", workflow_id, len(steps)) + db = await get_db() for step in steps: plugin_id = step.get("plugin_id") inputs = step.get("inputs") or {} diff --git a/frontend/testing/unit/pages/ToolConfigDynamic.test.tsx b/frontend/testing/unit/pages/ToolConfigDynamic.test.tsx index 6cd5a1da..03bfb13c 100644 --- a/frontend/testing/unit/pages/ToolConfigDynamic.test.tsx +++ b/frontend/testing/unit/pages/ToolConfigDynamic.test.tsx @@ -108,6 +108,11 @@ describe('ToolConfig dynamic schema flow', () => { }), true, 'quick', + expect.objectContaining({ + scan_profile: 'standard', + validation_mode: 'proof', + evidence_level: 'standard', + }), ) }) }) diff --git a/frontend/testing/unit/pages/ToolConfigTimeout.test.tsx b/frontend/testing/unit/pages/ToolConfigTimeout.test.tsx index 4c0b2213..513ca033 100644 --- a/frontend/testing/unit/pages/ToolConfigTimeout.test.tsx +++ b/frontend/testing/unit/pages/ToolConfigTimeout.test.tsx @@ -75,6 +75,6 @@ describe('ToolConfig timeout control', () => { // min from field.validation expect(input).toHaveAttribute('min', '30') // max is min(field.validation.max, server default_timeout) - expect(input).toHaveAttribute('max', '600') + expect(input).toHaveAttribute('max', '7200') }) }) diff --git a/frontend/testing/unit/pages/Workflows.test.tsx b/frontend/testing/unit/pages/Workflows.test.tsx index 7c304da8..54628a33 100644 --- a/frontend/testing/unit/pages/Workflows.test.tsx +++ b/frontend/testing/unit/pages/Workflows.test.tsx @@ -130,7 +130,15 @@ describe('Workflows — create action', () => { name: 'Nightly Scan', schedule_seconds: 7200, enabled: true, - steps: [{ plugin_id: '', inputs: {} }], + steps: [{ + plugin_id: '', + inputs: {}, + execution_context: { + scan_profile: 'standard', + validation_mode: 'proof', + evidence_level: 'standard', + }, + }], }) }) })