Back to skill

Security audit

Subnet Calc

Security checks for vulnerabilities and agentic risk

Overview

This is a straightforward subnet calculator, but its bundled script can exhaust memory or produce enormous output for valid broad CIDR inputs.

Install only if you trust users and agents not to pass broad or untrusted CIDR ranges. The skill does not show data theft or persistence, but it should be bounded or fixed before use in shared automation, services, or workflows that might process arbitrary network input.

Vulnerability Patterns
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (2)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/subnet_calc.py:31
Finding

Unbounded IPv4 Host Materialization Causes Memory Exhaustion

Content
View full analysis
0 and network.prefixlen < 31: hosts = list(network.hosts()) result["first_host"] = str(hosts[0]) result["last_host"] = str(hosts[-1]) elif network.prefixlen == 31: # RFC 3021 point-to-point hosts = list(network) result["first_host"] = str(hosts[0]) result["last_host"] = str(hosts[1]) ``` ### Technical Analysis For every IPv4 network with a prefix shorter than `/31`, the program converts the complete host iterator into a Python list merely to obtain its first and last elements. The number of allocated objects grows according to the size of the supplied network. For example, processing `0.0.0.0/0` attempts to materialize approximately 4.29 billion IPv4 addresses. The input is syntactically valid and passes `ipaddress.ip_network()` validation, but the resulting allocation can exceed available memory. No maximum network size, address-count threshold, or lazy calculation mechanism is applied. The first and last usable addresses can be calculated directly without enumerating intermediate addresses. ### Attack Path 1. An attacker or untrusted caller supplies a large valid IPv4 network, such as: ```bash python3 scripts/subnet_calc.py 0.0.0.0/0 ``` 2. `ipaddress.ip_network()` accepts and normalizes the CIDR value. 3. `calc_ipv4()` invokes `network.hosts()`. 4. `list()` attempts to allocate an object for every usable address. 5. The process consumes excessive memory and CPU time. 6. The operating system may terminate the process, or the host may become degraded due to memory pressure and swapping. ### Impact Assessment This issue does not grant additional privileges or provide access to confidential data. Its primary impact is availability. An attacker who can control the CIDR argument can ...[truncated 265 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/subnet_calc.py:89
Finding

Unbounded Subnet Splitting Causes Memory and Output Exhaustion

Content
View full analysis
list[str]: """Split a network into smaller subnets.""" if new_prefix <= network.prefixlen: print(f"Error: new prefix /{new_prefix} must be larger than /{network.prefixlen}", file=sys.stderr) sys.exit(1) if new_prefix > 32: print("Error: prefix cannot exceed /32", file=sys.stderr) sys.exit(1) return [str(subnet) for subnet in network.subnets(new_prefix=new_prefix)] ``` The returned list is then retained and fully rendered: ```python if args.split is not None: if isinstance(network, ipaddress.IPv6Network): print("Error: --split currently supports IPv4 only", file=sys.stderr) sys.exit(1) subnets = split_subnet(network, args.split) if args.fmt == "json": print(json.dumps({"parent": str(network), "subnets": subnets}, indent=2)) else: print(f" Splitting {network} into /{args.split} subnets ({len(subnets)} total):\n") for s in subnets: print(f" {s}") ``` ### Technical Analysis The validation checks only that the requested prefix is greater than the original prefix and does not exceed `/32`. It does not limit the number of generated subnets. The subnet count is: ```text 2 ** (new_prefix - current_prefix) ``` A request to split `0.0.0.0/0` into `/32` networks therefore attempts to create 4,294,967,296 subnet strings. The list comprehension eagerly retains every string in memory before any output is produced. JSON mode creates an additional serialized representation, further increasing peak memory use. Plain mode can also produce an extreme volume of output if list construction succeeds for a smaller but still excessive request. ### Attack Path 1 ...[truncated 1131 chars]
Remediation
View remediation
MAX_SUBNETS: raise ValueError( f"Requested split produces {subnet_count} subnets; " f"maximum allowed is {MAX_SUBNETS}" ) ``` Avoid returning an eagerly constructed list when plain streaming output is sufficient. Iterate over `network.subnets()` directly after enforcing a safe maximum. For JSON output, retain a strict limit because valid JSON requires bounded materialization or controlled streaming. Additional hardening should include: - Configure a conservative maximum subnet count appropriate for the execution environment. - Return errors through normal exception handling rather than calling `sys.exit()` inside the helper function. - Apply output-size, execution-time, and memory limits when exposing the CLI through a remote service. - Add tests for boundary cases such as `/0` to `/32`, requests exactly at the configured limit, and requests one subnet beyond the limit. ]]>
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep

Static analysis

No suspicious patterns detected.