Back to skill

Security audit

Email Finder

Security checks for vulnerabilities and agentic risk

Overview

This skill does what it advertises, but it actively discovers and verifies personal email addresses in ways users should review carefully before installing.

Install only if you are comfortable with a tool that contacts websites, DNS, Google, hunter.io, and recipient mail servers to find and verify email addresses. Use it only for authorized, targeted lookups, prefer --no-verify unless SMTP probing is necessary, and avoid using it to build unsolicited outreach lists or guess personal addresses without a legitimate basis.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
Findings (3)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/find_emails.py:54
Finding
TLS Certificate Validation Disabled for All HTTPS Requests<![CDATA[ ## Vulnerability Details **File Location**: `scripts/find_emails.py`, lines 54–59 **Vulnerability Type**: Improper certificate validation **Risk Level**: High ### Vulnerable Code ```python def fetch_page(url, timeout=10): """Fetch a URL and return its text content, or None on failure.""" try: req = Request(url, headers=HEADERS) ctx = ssl.create_default_context() ctx.check_hostname = False ctx.verify_mode = ssl.CERT_NONE with urlopen(req, timeout=timeout, context=ctx) as resp: ``` ### Technical Analysis The `fetch_page()` function explicitly disables both TLS hostname verification and certificate-chain validation. Consequently, every HTTPS connection made through this function accepts expired, self-signed, incorrectly issued, or attacker-controlled certificates. This affects connections to: - Websites being searched for email addresses - Google search endpoints - Hunter.io endpoints - Redirect destinations reached by `urlopen()` Although the network requests support the Skill's declared email-finding functionality, disabling certificate validation is not necessary for that functionality and exceeds safe minimum network privileges. It removes the server-authentication property normally provided by HTTPS. An attacker capable of intercepting network traffic can impersonate any requested HTTPS server and return manipulated content. Because the response is searched for addresses matching the target domain, the attacker can inject fabricated email addresses into the result. Those addresses may subsequently be submitted to the target MX server through SMTP verification. ### Attack Path 1. A user runs the Skill on a network controlled or monitored by an attacker. 2. The Skill requests a target website, Google, or Hunter.io over HTTPS. 3. The attacker intercepts the TLS connection and presents an attacker-controlled certificate. 4. The certificate is accepted because hostname and certificate validation ar ...[truncated 906 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Remove the insecure TLS context and rely on the platform's default certificate validation: ```python def fetch_page(url, timeout=10): try: req = Request(url, headers=HEADERS) with urlopen(req, timeout=timeout) as resp: data = resp.read(500_000) charset = resp.headers.get_content_charset() or 'utf-8' return data.decode(charset, errors='replace') except Exception: return None ``` Additional hardening should include: 1. Do not expose an option that disables certificate validation. 2. Use a trusted CA bundle if a custom certificate store is required. 3. Validate HTTPS redirects before following them. 4. Log TLS failures without silently retrying through an insecure connection. 5. Consider returning structured error information instead of catching every exception without distinction. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/find_emails.py:286
Finding
Unvalidated Target Domain Permits Requests to Unintended Network Services<![CDATA[ ## Vulnerability Details **File Location**: `scripts/find_emails.py`, lines 286–296; network sinks at lines 89–107 **Vulnerability Type**: Unrestricted outbound request target / server-side request forgery risk **Risk Level**: Medium ### Vulnerable Code The target is normalized only through string replacement: ```python args = parser.parse_args() domain = args.domain.lower().strip() do_verify = not args.no_verify # Remove protocol if provided domain = domain.replace('https://', '').replace('http://', '').strip('/') all_emails = {} # email -> {source, ...} # 1. Scrape website log("Step 1: Website scraping") scraped = scrape_website(domain, scrape_delay=args.scrape_delay) ``` It is then interpolated directly into outbound request URLs: ```python paths = ['/', '/contact', '/contact-us', '/about', '/about-us', '/team', '/our-team', '/people', '/staff'] base = f'https://{domain}' for path in paths: url = base + path log(f" GET {url}") text = fetch_page(url) ``` The same value is also transmitted to third-party services: ```python urls = [ f'https://www.google.com/search?q=%22%40{domain}%22', f'https://hunter.io/try/v2/domain-search?domain={domain}&type=personal', ] ``` ### Technical Analysis The positional `domain` argument is assumed to be a public DNS hostname, but it is not validated as one. Removing protocol text and slashes does not reject: - Loopback or private IP literals - Link-local or reserved destinations - Explicit ports - URL user-information delimiters - Query strings or fragments - Hostnames that resolve to private addresses - Public hosts that redirect to internal destinations The value controls website requests, DNS lookups, third-party query parameters, and potentially SMTP destinations derived from MX records. `urlopen()` can also follow redirects, but redirect destinations are not revalidated. The Skill legitimately requires outbound access to the selected public domain, public DNS infrastructure, s ...[truncated 1865 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Implement centralized target validation before performing DNS, HTTP, HTTPS, or SMTP operations: 1. Parse input as a hostname rather than modifying it with string replacement. 2. Accept only canonical DNS hostnames when IP-literal support is unnecessary. 3. Reject credentials, paths, query strings, fragments, and explicit ports. 4. Reject `localhost` and local-domain aliases. 5. Resolve all A and AAAA records and reject loopback, private, link-local, multicast, unspecified, and reserved addresses. 6. Revalidate the resolved address immediately before connecting to reduce DNS-rebinding risk. 7. Disable automatic redirects or validate every redirect destination using the same policy. 8. Apply the same address restrictions to MX hosts before opening port 25. 9. URL-encode third-party query parameters instead of directly interpolating input. 10. If operationally possible, enforce an outbound allowlist or network-level egress policy. A hostname validation routine should use `urllib.parse`, `ipaddress`, and explicit DNS resolution. Validation must cover every resolved IPv4 and IPv6 address, not only the first result. ]]>

T08 · Insecure Dependencies

Note
Location
SKILL.md:22
Finding
Unpinned Third-Party Dependency Installation<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md`, lines 22–26 **Vulnerability Type**: Unpinned software dependency **Risk Level**: Low ### Vulnerable Code ```bash pip3 install dnspython ``` ### Technical Analysis The installation instructions retrieve the latest version of `dnspython` available from the package index at installation time. No reviewed version, lock file, integrity hash, or reproducible dependency manifest is specified. The package name is consistent with the module imported by the script, and the reviewed project contains no evidence that it intentionally references a typosquatted or known-malicious package. The risk arises from unconstrained future package resolution rather than from demonstrated malicious behavior in the current source. An unpinned installation can unexpectedly select: - A future incompatible release - A compromised upstream release - A package affected by a newly introduced vulnerability - Different artifacts across environments ### Attack Path 1. A user follows the documented dependency installation command. 2. The package manager resolves whichever `dnspython` release is current at that time. 3. If that release or its distribution channel has been compromised, installation introduces attacker-controlled code. 4. Python imports the installed package when the Skill starts. 5. Malicious package initialization code would run with the same privileges as the user executing the Skill. This path is conditional; the audit found no evidence that the currently named package is malicious. ### Impact Assessment A compromised dependency could execute code with the privileges of the user running the Skill, potentially allowing access to that user's files, environment, and network permissions. An incompatible but non-malicious update could also break DNS analysis or alter behavior unexpectedly. The current project does not request administrator privileges and does not instruct users to install from an untrusted ...[truncated 114 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Pin a reviewed dependency release in a requirements file: ```text dnspython==<reviewed-version> ``` For stronger supply-chain protection: 1. Generate and verify package hashes. 2. Install with `pip install --require-hashes -r requirements.txt`. 3. Commit the dependency manifest or lock file to the project. 4. Review and deliberately update dependency versions. 5. Run automated vulnerability and license scanning against locked dependencies. 6. Use a trusted package index and avoid unreviewed alternate indexes. 7. Document the supported Python and dependency versions. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (7)

Lp3

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding
The skill clearly performs network actions including web scraping, DNS lookups, search queries, and SMTP recipient verification, but it declares no explicit tool scope or permission boundary. That mismatch can let the skill be invoked with broader network capability than users or policy expect, reducing visibility and control over outbound interactions with third-party systems.

Vague Triggers

Medium
Confidence
95% confidence
Finding
The description is framed broadly around prospecting leads, outreach, and building contact lists, which can cause the skill to be selected for common business requests without sufficient scrutiny. Because the skill performs personal data discovery and active verification against mail servers, broad invocation language increases the chance of privacy-invasive or policy-violating use in routine workflows.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The skill explicitly supports generating likely personal email addresses from a person's name and verifying them via SMTP, but the description lacks a clear privacy, consent, and anti-harassment warning. In context, this makes the capability more dangerous because it facilitates identifying and validating personal contact data for outreach or targeting, which can enable spam, stalking, or unauthorized profiling.

Missing User Warnings

Medium
Confidence
87% confidence
Finding
The search and scraping logic sends requests containing the target domain to external sites, including Google and hunter.io, without clearly warning that target information will be disclosed to third parties. In a lead-generation/email-finding skill this is especially sensitive because the queried domains and patterns can reveal prospecting targets, investigations, or internal workflow, creating privacy and operational exposure.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The script performs active SMTP RCPT probing against third-party mail servers, which discloses the operator's interest in specific domains and guessed addresses and may trigger logging, blocking, or abuse responses. In this skill context, email enumeration and validation are core features, so the behavior is intentional, but the lack of explicit warning/consent and the default-on verification make the privacy and policy risk materially higher.

Intent-Code Divergence

Low
Confidence
97% confidence
Finding
The docstring states that, because web_search is unavailable, the function will 'try common directories.' However, the implementation constructs outbound requests to a Google search URL and a hunter.io domain-search endpoint instead of directory pages. This is a direct contradiction between documentation and behavior, not merely omitted detail.

Intent-Code Divergence

Low
Confidence
94% confidence
Finding
The CLI defines '--verify' as a store_true flag with default=True, so it does not meaningfully enable anything that was disabled; verification is actually governed by 'do_verify = not args.no_verify'. This makes the documented behavior of the '--verify' option misleading relative to the code's actual control flow.

Static analysis

No suspicious patterns detected.