T09 · Insecure Skill Coding Practices
Error
- Location
- main.py:27
- Finding
- Unvalidated Input Permits Injection of Additional Nmap Arguments<![CDATA[ ## Vulnerability Details **File Location**: `main.py`, lines 27–28, 45–50, and 94–95 **Vulnerability Type**: Nmap argument injection through insufficient input validation **Risk Level**: High ### Vulnerable Code ```python if exclude: scan_options += f' --exclude {exclude}' ``` The `exclude` value originates directly from command-line input: ```python elif arg.startswith("--exclude="): exclude = arg.split("=")[1] ``` Range and comma-separated targets are also passed to the scanner without validating their individual addresses: ```python elif '-' in target: start_ip, end_ip = target.split('-') results = scanner.scan(start_ip+'-'+end_ip, ports, arguments=scan_options) elif ',' in target: results = scanner.scan(target, ports, arguments=scan_options) ``` ### Technical Analysis The implementation constructs the Nmap argument string by directly interpolating the attacker-controlled `exclude` value. Although the documentation describes this value as a single IP address, the code does not validate it with `ipaddress.ip_address()`, reject whitespace, or ensure that it contains only one address. Consequently, a value containing an address followed by additional Nmap options can alter the command interpreted by Nmap. This is Nmap argument injection rather than conventional shell-command injection: there is no evidence that shell metacharacters are directly evaluated by a shell, but an attacker can potentially access powerful Nmap functionality such as NSE script selection, script arguments, alternate configuration options, output controls, or more aggressive scan modes. The same validation weakness affects range and comma-separated targets. Unlike single-IP and CIDR targets, these formats are selected merely by checking for `-` or `,`, after which the unvalidated value is passed to `scanner.scan()`. The `ports` parameter is also passed through without an explicit application-level allowlist. ### Attack Path 1. An attacker obtains th ...[truncated 1811 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Validate `exclude` as exactly one IP address before constructing Nmap arguments: ```python if exclude: try: validated_exclude = str(ipaddress.ip_address(exclude)) except ValueError: return {"error": "Invalid exclusion address."} scan_options += f" --exclude {validated_exclude}" ``` 2. Validate every component of comma-separated target lists: ```python targets = target.split(",") if not targets or not all(is_valid_ipv4_address(item.strip()) for item in targets): return {"error": "Invalid comma-separated target list."} target = ",".join(str(ipaddress.ip_address(item.strip())) for item in targets) ``` 3. Parse ranges with a bounded split and independently validate both endpoints. Confirm that both addresses use the same IP version and that the start address does not exceed the end address. 4. Strictly validate the `ports` parameter against an allowlist grammar. Accept only port numbers and explicitly supported ranges, enforce values from 1 through 65535, and reject whitespace or option-like tokens. 5. Enforce safe bounds for numeric options: - Require `timeout` to be a positive integer with a reasonable maximum. - Require `top_ports` to be within Nmap-supported limits. - Require `hosts_limit` to be positive and capped according to the deployment policy. 6. Reject control characters, unexpected whitespace, and values beginning with `-` in all fields that can reach Nmap. 7. Prefer structured argument construction where supported by the dependency. Do not combine user-controlled values into a free-form option string. 8. Run the Skill under a dedicated, minimally privileged account. Avoid unnecessary root execution and restrict access to local NSE script directories and sensitive files. 9. Add regression tests that verify injected tokens such as additional Nmap options are rejected for `exclude`, targets, and ports before Nmap is invoked. ]]>
