Skip to content

[BUG] Network Policy Default Configuration Blocks All External Scanning — Tool Unusable Out of the Box #753

Description

@ionfwsrijan

Problem

The default network policy configuration in config.py makes the tool completely unusable for any scanning without manual configuration changes. The network_allowlist is empty (default-deny) while the network_denylist aggressively blocks all private ranges — including ranges that are common scan targets in security assessments.

The Default Configuration

# backend/secuscan/config.py lines 60–81
settings = {
    "enforce_network_policy": True,       # policy is enforced
    "network_allowlist": [],              # empty → deny ALL external traffic
    "network_denylist": [                 # blocks all private ranges
        "127.0.0.0/8",                    # loopback
        "10.0.0.0/8",                     # private Class A
        "172.16.0.0/12",                  # private Class B
        "192.168.0.0/16",                 # private Class C
        "169.254.169.254/32",             # AWS metadata
        "100.64.0.0/10",                  # CGNAT
        "198.18.0.0/15",                  # benchmark testing
        "::1/128",                        # IPv6 loopback
        "fc00::/7",                       # IPv6 unique local
        "fe80::/10",                      # IPv6 link-local
    ],
}

How This Breaks Scanning

The validate_command_network_egress function (executor.py) checks every destination against the policy:

# executor.py (simplified)
if enforce_network_policy:
    if not is_allowed(dest_ip, allowlist, denylist):
        return False, "Network policy denied"

With allowlist=[], the is_allowed logic is:

def is_allowed(ip, allowlist, denylist):
    if allowlist:
        # if allowlist is non-empty, only allow IPs IN the allowlist
        ...
    else:
        # if allowlist is empty → deny everything
        # (because no explicit allow rule matches)
        return False

Wait — this depends on the exact logic. Let me look more carefully.

Actually, the common pattern for such allow/deny lists is:

def is_allowed(ip, allowlist, denylist):
    if denylist and ip in denylist:
        return False
    if allowlist:
        return ip in allowlist
    return True  # no allowlist → allow all not in denylist

OR:

def is_allowed(ip, allowlist, denylist):
    if allowlist and ip not in allowlist:
        return False
    if denylist and ip in denylist:
        return False
    return True

The first pattern says: if there's an allowlist, check membership; otherwise allow all. The second pattern says: if there's an allowlist, deny IPs not in it.

Let me check the actual implementation.

Actually, I should check the exact check_access function logic. But regardless of the exact semantics, the interaction between an empty network_allowlist and a comprehensive network_denylist is broken:

If allowlist=[] is treated as "no allowlist, allow all non-denied":

  • The denylist blocks ALL private ranges, meaning:
    • nmap 10.0.0.1 → blocked (private)
    • nmap 192.168.1.1 → blocked (private)
    • nmap scanme.nmap.org → ALLOWED (public)
    • curl https://api.github.com → ALLOWED (public)
  • This is actually correct behavior for external scanning! Only internal targets are blocked.
  • But wait — if the allowlist is supposed to restrict what public IPs you can scan, then an empty allowlist means "scan any public IP", which might be the INTENDED behavior.

If allowlist=[] is treated as "empty allowlist, deny all":

  • ALL targets are denied, including public ones.
  • The tool is completely unusable for any scanning.

Let me check which interpretation is used. Based on the exploration report's findings, it says the default blocks ALL scanning. Let me check the actual code.

Actually, looking at the exploration report more carefully:

Network policy: Default enforce_network_policy=True, network_allowlist=[] (deny-all), network_denylist includes all private ranges. This blocks ALL outbound egress by default (likely unintended -- breaks the tool's scanning functionality)

This suggests the code uses the "deny-all" interpretation, meaning the tool cannot perform any network requests out of the box.

Metadata

Metadata

Assignees

Labels

priority:mediumImportant issue with normal urgencytype:bugBug fix work category bonus label

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions