Back to skill

Security audit

Netmap

Security checks for vulnerabilities and agentic risk

Overview

This local network mapping skill is mostly coherent, but it automatically sends device MAC addresses to a third-party service and allows broad scan targets without enforcing its stated local-network boundary.

Install only if you are comfortable with active network scanning and local retention of device inventory. Before using it on a work or shared network, review policy and consider disabling or removing the online MAC vendor lookup, limiting scans to your own local subnet, and avoiding watch or deep mode unless you explicitly need them.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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)

other

Warning
Location
scripts/netmap.py:58
Finding
Undisclosed Third-Party Disclosure of Device MAC Addresses<![CDATA[ ## Vulnerability Details **File Location**: `scripts/netmap.py:49-70`, with the external disclosure occurring at lines 58-60 **Vulnerability Type**: Privacy Data Disclosure **Risk Level**: Medium ```python def lookup_vendor(mac): """Look up vendor for a MAC address, with local caching.""" if not mac: return None prefix = mac[:8].upper() # First 3 octets cache = load_vendor_cache() if prefix in cache: return cache[prefix] try: resp = urllib.request.urlopen( f'https://api.macvendors.com/{mac}', timeout=3 ) vendor = resp.read().decode('utf-8').strip() if vendor and 'Not Found' not in vendor: cache[prefix] = vendor save_vendor_cache(cache) return vendor except Exception: pass cache[prefix] = None save_vendor_cache(cache) return None ``` ### Technical Analysis The function sends the complete MAC address of each uncached device to `api.macvendors.com` over HTTPS. MAC addresses are stable identifiers for devices on a private network and can reveal manufacturer information and aspects of the user's device inventory. This external lookup occurs automatically when a scan discovers a MAC address without vendor metadata. It is also applied to historical database entries that have a MAC address but no known vendor. Although HTTPS protects the request in transit, it does not prevent the external service from observing the submitted MAC address, the user's public source IP, request timing, and repeated inventory changes. The declared functionality requires vendor identification, but it does not strictly require disclosure of full MAC addresses to an external service. `SKILL.md` does not disclose this third-party transmission or provide an opt-in or offline-only mode. ### Attack Path 1. The user invokes `python3 scripts/netmap.py scan` or starts watch mode. 2. The script discovers devices through `nmap` and the local ...[truncated 1207 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Make all external vendor lookups disabled by default and require an explicit option such as `--online-vendor-lookup`. 2. Clearly disclose in `SKILL.md` that enabling the option transmits device identifiers to a third party. 3. Prefer a bundled or locally maintained IEEE OUI database so vendor resolution remains offline. 4. If remote resolution is retained, submit only the first three octets—the OUI prefix—rather than the complete MAC address, provided the service supports prefix queries. 5. Request explicit user confirmation before the first external lookup. 6. Provide an option to disable vendor enrichment permanently. 7. Document the external service, transmitted data, retention implications, and cache behavior. 8. Apply restrictive permissions to `vendor_cache.json` because it records information derived from the local device inventory. ]]>

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
scripts/netmap.py:121
Finding
Unrestricted Scan Target Allows Probing of Remote or Excessively Broad Networks<![CDATA[ ## Vulnerability Details **File Location**: `scripts/netmap.py:121-132`, with user-controlled target registration and forwarding at lines 463-465 and 490 **Vulnerability Type**: Unrestricted Network Reconnaissance Target **Risk Level**: Medium ```python def run_nmap(subnet, fast=True): """Run nmap host discovery.""" print(f" Scanning {subnet} (this may take 30-60s)...") cmd = [ NMAP_PATH, '-sn', # Ping scan — discovers live hosts '-oX', '-', # XML output to stdout '--host-timeout', '15s', subnet ] result = subprocess.run(cmd, capture_output=True, text=True) return result.stdout ``` The target is exposed through the command-line interface and forwarded to the scan operation: ```python scan_p = subparsers.add_parser('scan') scan_p.add_argument('--subnet', help='Override subnet (e.g. 10.0.0.0/24)') scan_p.add_argument('--deep', action='store_true', help='Port scan each device to fingerprint type (slower)') ``` ```python if args.command == 'scan': scan(subnet=getattr(args, 'subnet', None), deep=getattr(args, 'deep', False)) ``` ### Technical Analysis The `--subnet` argument accepts an arbitrary string and passes it directly to `nmap` as a target. The implementation does not verify that the target: - Is a valid IP network in CIDR notation. - Uses a private, link-local, or otherwise approved address range. - Overlaps a network configured on an active local interface. - Has a safe maximum host count. - Is authorized by the user who controls the target network. Using a subprocess argument list prevents conventional shell metacharacter injection, so this is not a shell-command injection vulnerability. However, it does not constrain the network scope of the underlying `nmap` operation. This behavior conflicts with the declared restriction in `SKILL.md`, which states that the Skill should not be used for remote networks. That restriction is advisory only and is not enfo ...[truncated 1766 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Parse the supplied target with Python's `ipaddress.ip_network()` using strict validation. 2. Reject hostnames, target lists, ranges, and other `nmap` target expressions; accept only a single bounded CIDR. 3. Require the network to be private or link-local unless a separately authorized operating mode is explicitly enabled. 4. Enumerate active local interfaces and verify that the requested subnet overlaps a directly connected network. 5. Impose a minimum prefix length or maximum host count, such as limiting IPv4 scans to `/24` or a comparably bounded range. 6. Reject loopback, multicast, unspecified, reserved, and public address ranges by default. 7. Apply the same target authorization checks before every deep port scan. 8. Require explicit confirmation when `--subnet` overrides automatic detection. 9. Add execution timeouts and handle nonzero `nmap` return codes. 10. Update `SKILL.md` to describe enforced network boundaries rather than relying only on advisory usage instructions. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
Findings (17)

Lp3

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding
The skill invokes shell commands, performs network scanning, and maintains a persistent local database, but it does not declare any explicit tool scope or permissions boundaries. That creates an authorization and transparency gap: an agent may execute network probing and local file writes without the skill clearly constraining or disclosing those capabilities.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The skill states that it maintains a persistent device database containing network inventory details, but it does not present this as a clear user warning or consent-sensitive behavior. Persistently storing IPs, MACs, hostnames, vendors, labels, and timestamps can expose household or enterprise network topology and device presence over time if the machine or account is later accessed by another party.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
The deep scan and watch mode repeatedly probe local devices and, in the case of deep scan, perform port scanning for fingerprinting, but the skill does not clearly warn users about the visibility and privacy implications of that activity. Repeated active scanning can trigger network monitoring alerts, violate local policy expectations, or unintentionally profile devices more aggressively than a user realizes.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
VENDOR_CACHE_FILE = Path.home() / '.config' / 'netmap' / 'vendor_cache.json'
DB_FILE.parent.mkdir(parents=True, exist_ok=True)

NMAP_PATH = subprocess.run(['which', 'nmap'], capture_output=True, text=True).stdout.strip() or 'nmap'


def load_vendor_cache():
Confidence
70% confidence
Finding
The code discovers nmap with 'which nmap' and falls back to invoking 'nmap' by name later, relying on the current PATH. If the tool runs in a context with a manipulated PATH, a malicious executable named nmap could be executed instead, resulting in arbitrary code execution under the user's privileges.

Description-Behavior Mismatch

Medium
Confidence
98% confidence
Finding
The skill sends discovered device MAC addresses to api.macvendors.com for vendor enrichment, but the skill description presents the tool as local-network mapping and does not disclose this external data transmission. MAC addresses are persistent device identifiers, so leaking them to a third party exposes network inventory metadata and may violate user expectations or privacy requirements.

Missing User Warnings

Medium
Confidence
98% confidence
Finding
The code transmits MAC addresses to an external API without any explicit warning at runtime or in the module description. Because MAC addresses identify devices on the user's network, undisclosed transmission weakens privacy and informed consent.

External Transmission

Medium
Category
Data Exfiltration
Content
return cache[prefix]
    try:
        resp = urllib.request.urlopen(
            f'https://api.macvendors.com/{mac}', timeout=3
        )
        vendor = resp.read().decode('utf-8').strip()
        if vendor and 'Not Found' not in vendor:
Confidence
98% confidence
Finding
This line sends a discovered MAC address to a third-party service over the internet. In a network-mapping tool, that exposes sensitive inventory information outside the local environment and may breach privacy expectations or policy constraints.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
"""Auto-detect the local network subnet (e.g. 192.168.0.0/24)."""
    try:
        # Get default gateway interface IP
        result = subprocess.run(
            ['python3', '-c',
             'import socket; s=socket.socket(socket.AF_INET,socket.SOCK_DGRAM); '
             's.connect(("8.8.8.8",80)); print(s.getsockname()[0]); s.close()'],
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
def get_arp_table():
    """Get MAC addresses from ARP cache without sudo (macOS/Linux)."""
    macs = {}
    try:
        result = subprocess.run(['/usr/sbin/arp', '-a'], capture_output=True, text=True, timeout=5)
Confidence
70% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
def get_arp_table():
    """Get MAC addresses from ARP cache without sudo (macOS/Linux)."""
    macs = {}
    try:
        result = subprocess.run(['/usr/sbin/arp', '-a'], capture_output=True, text=True, timeout=5)
Confidence
70% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
"""Get MAC addresses from ARP cache without sudo (macOS/Linux)."""
    macs = {}
    try:
        result = subprocess.run(['/usr/sbin/arp', '-a'], capture_output=True, text=True, timeout=5)
        out = result.stdout
    except Exception:
        try:
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
out = result.stdout
    except Exception:
        try:
            result = subprocess.run(['arp', '-a'], capture_output=True, text=True, timeout=5)
            out = result.stdout
        except Exception:
            return macs
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
'--host-timeout', '15s',
        subnet
    ]
    result = subprocess.run(cmd, capture_output=True, text=True)
    return result.stdout
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Context-Inappropriate Capability

Medium
Confidence
92% confidence
Finding
Deep mode performs active port scans against each discovered host, which goes beyond simple device listing and may trigger IDS alerts, violate policy, or probe services users did not intend to touch. In the context of a home/office inventory skill, this additional behavior increases operational risk unless it is prominently disclosed and explicitly requested.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
def run_nmap_ports(ip):
    """Quick port scan to fingerprint device type."""
    try:
        result = subprocess.run(
            [NMAP_PATH, '-F', '--open', '-oX', '-', '--host-timeout', '10s', ip],
            capture_output=True, text=True, timeout=20
        )
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Missing User Warnings

Low
Confidence
88% confidence
Finding
The tool persistently stores a device inventory including IPs, MACs, hostnames, labels, and timestamps in the user's home directory, but this retention is not clearly disclosed in the command description. Persistent network inventory can be sensitive on shared systems or if local files are later exposed.

Description-Behavior Mismatch

Low
Confidence
90% confidence
Finding
Subnet autodetection opens a socket to 8.8.8.8 to infer the local source IP, which creates outbound internet traffic despite the tool being described as local-network scanning. Even if no payload is sent beyond connection setup, this can surprise users in restricted environments and leak metadata about tool use.

Static analysis

No suspicious patterns detected.